【问题标题】:Receiving `UnhandledPromiseRejectionWarning` even though rejected promise is handled即使处理了被拒绝的承诺,也会收到“UnhandledPromiseRejectionWarning”
【发布时间】:2017-04-19 05:18:50
【问题描述】:

我构造了一个函数,它遍历包含同步代码和PromisesGenerator

module.exports = {


    isPromise (value) {
            return typeof value === 'object' && value !== null && 'then' in value;
        },

    runGen (generatorFunc, startValue) {

            let that = this,
                i = 0;

            function *iterator(resolve, reject) {

                let runGeneratorFunc = generatorFunc(startValue),
                    yieldedOut = {done: false},
                    yieldIn;

                while (!yieldedOut.done) {
                    console.log(i++, 'Ready for next iteration');
                    if (that.isPromise(yieldedOut.value)) {
                        console.log(i++, 'Pass promise to KeepIterating');
                        yieldIn = yield yieldedOut.value;
                        console.log(i++, 'Received value from promise');

                        if(yieldIn instanceof Error){
                            console.log(i++, 'Value was instance of Error');
                            try {
                                yieldedOut = runGeneratorFunc.throw(yieldIn)
                            }
                            catch(err){
                                console.log(i++, 'Throw Error');
                                throw(yieldIn);
                            }
                        } else {
                            yieldedOut = runGeneratorFunc.next(yieldIn);
                        }
                    } else {
                        try {
                            yieldIn = yieldedOut.value;
                            yieldedOut = runGeneratorFunc.next(yieldIn);
                        }
                        catch(err) {
                            runGeneratorFunc.throw(err);
                            reject(err);
                        }
                    }
                }
                resolve(yieldedOut.value);
            }

            return new Promise(function (resolve, reject) {
                var runIterator = iterator(resolve, reject);
                (function keepIterating(yieldIn) {
                    let yieldedOutPromise = runIterator.next(yieldIn);

                    if (!yieldedOutPromise.done) {

                        yieldedOutPromise.value.then(function (fulfilledValue) {
                            console.log('never gets here');
                            keepIterating(fulfilledValue);
                        });

                        yieldedOutPromise.value.catch(function (err) {
                            console.log(i++, 'Rejected promise catched');
                            if (err instanceof Error) {
                                try {
                                    console.log(i++, 'Rejected promise is instance of Error');
                                    let yieldedOut = runIterator.next(err);
                                    keepIterating(yieldedOut);
                                }
                                catch (err) {
                                    console.log(i++, 'Error propagated back out');
                                    yieldedOutPromise.value.catch(() => {})
                                    reject(err);
                                }
                            } else {
                                try {
                                    let yieldedOut = runIterator.next(new Error(err));
                                    keepIterating(yieldedOut);
                                }
                                catch (err) {
                                    reject(err);
                                }
                            }
                        })
                    }
                })();
            });
        }
    }

现在,当我使用此代码导入并运行它时:

const md = require('./module');

function* dummy () {
    yield Promise.reject(new Error('error1'));
}

md.runGen(dummy)
.catch(err => {
    console.log(9, 'Finished!');
})

我将此记录到控制台:

0 'Ready for next iteration'
1 'Ready for next iteration'
2 'Promise yielded out'
3 'Rejected promise handled'
4 'Rejected promise instance of Error'
5 'Ready to handle promise value'
6 'Value was instance of Error'
7 'Throw Error'
8 'Error propagated back out'
9 'Finished!'
(node:9904) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: error1
(node:9904) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

除了关于UnhandledPromiseRejectionWarning 的警告之外,这一切都符合预期。我很困惑为什么我会收到这个警告,因为据我所知,在代码中处理了被拒绝的Promise

我忽略了什么?

【问题讨论】:

  • 有语法错误吗?
  • 否,输出与上面显示的完全一样。没有遗漏任何内容
  • 你真的不应该自己写这些函数。立即使用提供它的库(例如Bluebird.coroutine)或使用async/await 语法(使用适当的转译器)。

标签: javascript node.js runtime-error generator es6-promise


【解决方案1】:

我忽略了什么?

您的yieldedOutPromise.value.then 调用正在创建一个新的承诺,如果yieldedOutPromise.value 拒绝,那么它也会被拒绝。你通过yieldedOutPromise.value上的.catch处理错误没关系,周围仍然有一个被拒绝的promise,它就是将被报告的那个。

你基本上是在拆分你的承诺链,这导致每一端都需要一个错误处理程序。但是,您根本不应该拆分任何东西。而不是

promise.then(onSuccess);
promise.catch(onError);

你应该使用的反模式

promise.then(onSuccess, onError).…

哦,当您使用它时,avoid the Promise constructor antipattern。做吧

module.exports = function runGen (generatorFunc, startValue) {
    return Promise.resolve(startValue).then(generatorFunc).then(generator => {
        return keepIterating({done: false, value: undefined});
        function keepIterating({done, value}) {
            if (done) return value;
            return Promise.resolve(value).then(fulfilledValue =>
                generator.next(fulfilledValue)
            , err =>
                generator.throw(err)
            ).then(keepIterating);
        }
    });
};

【讨论】:

  • 您提出的解决方案未返回预期结果。
  • @guest271314 你什么意思?什么是“预期结果”,OP 得到的输出日志?它给你带来了什么?
  • 你的方法没有达到console.log('never gets here');
  • @guest271314 Except that's not the same。链接value.then(…).catch(…) 不是我们想要的。
  • @guest271314 正如链接所解释的,您需要考虑onFulfilled 抛出的情况。诚然,这不会发生在您的代码中,而仅仅是因为您仍然使用了 Promise 构造函数反模式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-16
  • 1970-01-01
  • 2019-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多