Почему ошибка не перехватывается в этой асинхронной функции NodeJS? - PullRequest
0 голосов
/ 03 июля 2018

Я пытаюсь понять, почему блок catch в функции загрузки не захватывает исключение, выброшенное после строки запроса (.....) в функции createReleaseVersion. Сценарий nodejs аварийно завершает работу, а исключение не обрабатывается. В консоли отображается только ошибка исключения.

В следующем коде я ожидал, что будет напечатано «получил тебя» потом «после», но этого не происходит.

Если я заменю throw на return reject (... тот же объект), то получу желаемый результат.
Я сначала напечатал «получил тебя», затем «после»

function createReleaseVersion(releaseVersion) {
    var options = {
        uri: 'https://someurl',
        method: 'POST',
        json: {'version': releaseVersion}
    };

    return new Promise(function(resolve, reject) {
        request(options, function (error, response, body) {
            throw {
                error: error,
                response: response,
                body: body
            };
            console.log(body);
            if (error) {
                throw {
                    error: error,
                    response: response,
                    body: body
                };
            } else {
                resolve();
            }
        });
    });
}

async function upload(releaseVersion) {
    try {
        await createReleaseVersion(releaseVersion);
    } catch (error) {
        console.log('got you');
    }
    console.log('after');
}

upload('ddd');

1 Ответ

0 голосов
/ 03 июля 2018

Хорошо, давайте возьмем более простой случай:

new Promise((resolve, reject) => {
  setTimeout(() => { throw new Error(); });
});

Что приводит к сбою процесса. Причина в том, что setTimeout (или request в вашем случае) подписывается на обратный вызов для последующего вызова .

Когда обратный вызов в конце концов вызывается - конструктор обещания уже выполняется, и ошибка выдается в текущий контекст (setTimeout / request's).

Причина, по которой конструктор обещает синхронно ловить ошибки, заключается в том, что он в основном делает это:

try {
   executor(resolve, reject); // your code
} catch (e) {
   reject(e);
}

Поскольку в вашем случае функция не выполняется синхронно - у нее нет возможности узнать о контексте исключения. Это может измениться в будущем с Зонами, но, вероятно, не изменится.

Если вы хотите пометить ошибку внутри обещанной функции - вы можете вызвать второй аргумент (reject) и reject(new Error(...)).

Я настоятельно рекомендую использовать util.promisify вместо того, чтобы вручную преобразовывать API в обещания, чтобы избежать подобных проблем:)

Я также рекомендую отклонять только объекты Error для лучшей трассировки стека.

...