Почему я получаю необоснованное отклонение обещания в этой ситуации? - PullRequest
0 голосов
/ 15 января 2020

У меня есть следующая функция в моем коде, которая может прервать выполнение по нескольким причинам:

const getAndCheckItem = async (itemId) => {
    try {
        const item = await getItem(itemId);
        if(item.firstFail) {
            throw "First fail";
        }
        if(item.secondFail) {
            throw "Second fail";
        }
        if(notGood(item)) {
            throw "Third fail"; 
        }

        return item;
    }
    catch(err) {
        return Promise.reject(err);
    }
};

Если я вызову ее внутри какой-то другой функции asyn c следующим образом, все в порядке и любой внутренний бросок обрабатывается:

try {
    item = await getAndCheckItem(ids[0]);
}
catch(err) {
    // handle error
}

Однако, когда я вызываю функцию для нескольких идентификаторов:

try {
    items = await Promise.all([ids.map(value => getAndCheckItem(value))]);
}
catch(err) {
    // handle error
}

, я получаю необработанное отклонение обещания в случае любого внутреннего броска. Я понимаю, что Promise.all () рассматривает любое возвращенное значение, не являющееся обещанием, как разрешенное обещание. Тем не менее, Promise.reject(err) должен возвращать Обещание и, следовательно, обрабатываться. В чем проблема?

1 Ответ

2 голосов
/ 15 января 2020

Promise.all () рассматривает любое возвращенное значение не обещания как разрешенное обещание.

Конечно, но когда вы делаете

return Promise.reject(err);

, вы возвращая Обещание, поэтому, как только он будет развернут вызывающим абонентом, вызов getAndCheckItem приведет к отклонению Обещания. Выполнение return Promise.reject(err) очень похоже на выполнение throw err внутри чего-то async.

Если все, что вы делаете в catch, это повторно бросить или вернуть отклоненное Обещание, в этом нет особого смысла - Вы также можете полностью оставить эту часть и просто позволить вызывающей стороне обработать ее:

const getAndCheckItem = async (itemId) => {
  const item = await getItem(itemId);
  if(item.firstFail) {
    throw "First fail";
  }
  if(item.secondFail) {
    throw "Second fail";
  }
  if(notGood(item)) {
    throw "Third fail"; 
  }
  return item;
}

В настоящее время вы также передаете массив массивов Обещаний Promise.all:

await Promise.all([ids.map(value => getAndCheckItem(value))]);

В этом случае Promise.all ничего не сделает, поскольку единственным элементом его массива является не-Promise (другой массив). Если какое-либо из внутренних обещаний будет отклонено, они не будут обработаны, поэтому вы получите необработанное отклонение.

Вместо этого передайте массив Обещаний Promise.all:

await Promise.all(ids.map(value => getAndCheckItem(value)));

Или, более кратко:

await Promise.all(ids.map(getAndCheckItem));
...