Почему я получаю неожиданное поведение при реализации Promise.race()?

#javascript #promise

Вопрос:

У меня есть код для реализации Promise.race (), и он в основном работает. Однако в данном случае:

 promiseRace([Promise.reject('test_error'), Promise.resolve('test_value')])
 

Я получаю test_value вместо test_error этого .
Почему это происходит?

 const promiseRace = promises => new Promise((resolve, reject) => {
  promises.forEach(p => {
    if (
      typeof p === 'object'
          amp;amp; 'then' in p
          amp;amp; typeof p.then === 'function'
    ) {
      p.then(resolve).catch(reject);
    } else {
      resolve(p);
    }
  });
});

promiseRace([Promise.reject('test_error'),
  Promise.resolve('test_value')]).then(value => { console.log(value); }); 

Комментарии:

1. Можете ли вы объяснить, почему, по вашему мнению, результат должен быть test_error таким ? Я знаю Promise.race результаты test_error , но почему вы думаете, что ваш код тоже должен это делать? Расскажите нам о своих рассуждениях о том, для чего предназначена каждая строка в вашей функции, чтобы люди могли указать, где ваши предположения не совпадают с тем, как JS был разработан для работы. Кроме того, обратите внимание, что вам не нужно такое большое утверждение «если», if (p instanceof Promise) это все, что вам нужно. Также обратите внимание, что вы не заботитесь о сохранении» this «, поэтому писать это как обычно function promiseRace(promises) { ... } было бы нормально.

2. Этот вариант менее красив, однако, если речь идет о двух вкладках (да, в этом случае instanceof оправдан), то с instanceof возникнут проблемы, потому что если вы передадите код с одной вкладки на другую — там будут разные объекты Promise

3. Это не имеет значения? Если это обещание, p instanceof Promise то это правда, конец. Передаете вы код или нет, не имеет значения: все, что является обещанием, является обещанием и, следовательно, является экземпляром типа Promise объекта.

4. Вместо того, чтобы самостоятельно выполнять проверку, просто позвоните Promise.resolve(p)

5. @Mike’Pomax’Camermans Были бы — если бы обещания не были предшествующими символами 🙂

Ответ №1:

Это происходит потому, что в следующей строке вы вызываете .catch другое (связанное) обещание, а не исходное обещание:

   p.then(resolve).catch(reject);
 

Обратите внимание, что then вызов не получает reject аргумент обратного вызова, и поэтому существует дополнительный-промежуточный асинхронный цикл обещания. К моменту .catch вызова обратного вызова ( reject ) другой случай уже был рассмотрен (выполненное обещание).

Поэтому измените на:

   p.then(resolve, reject);