javascript - ES6 Promise 错误没有按预期冒泡

标签 javascript error-handling promise ecmascript-6

我从 E6 Promises 开始。我非常喜欢它们,但有一个关于错误处理的关键概念我不明白,希望得到一些澄清。

让我们假设以下返回 promise 的简单函数:

    function promiseString(str, timeout, doResolve) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                if (doResolve) {
                    resolve(str);
                } else {
                    reject(new Error("Rejecting " + str));
                }
            }, timeout);
        });
    }

它非常简单,只是为传递给它的字符串返回一个 promise ,并导致该 promise 在“超时”毫秒内被解决或拒绝(基于第三个参数)。

我可以按预期完全使用它,如下所示:

            promiseString("One", 100, true)
                .then((str) => { console.log("First then is " + str); return promiseString(str + " two", 100, true); })
                .then((str) => { console.log("Second then is " + str); return promiseString(str + " three", 100, true); })
                .then((str) => console.log(str))
                .catch((err) => console.error(err));

如果在此链中的任何调用中将第三个参数从“true”更改为“false”,我的错误将按预期捕获并发送到 console.error()。

但是,现在想象以下(同样愚蠢的)函数来构造一个有前途的对象:

    function DoublePromiser(str1, str2, doResolve) {
        this.promise = new Promise((resolve, reject) => {
            promiseString(str1, 100, doResolve)
                .then((s1) => promiseString(s1 + str2, 100, doResolve))
                .then((s2) => resolve(s2));
        });
    }

想象一下,现在我按如下方式使用这段代码,所有内容都解析,没有任何内容拒绝,(doResolve 设置为 true):

            var dp = new DoublePromiser("Big", "Promise", true);
            dp.promise
                .then((s) => console.log("DoublePromise: " + s))
                .catch((err)=>console.log("I did catch: ", err.message));

正如预期的那样,我在控制台中看到以下内容:

DoublePromise: BigPromise

但是,现在我更改了消费代码,将 doResolve 设置为“false”(这导致我的 promise 例程被拒绝):

            var dp = new DoublePromiser("Big", "Promise", false);
            dp.promise
                .then((s) => console.log("DoublePromise: " + s))
                .catch((err)=>console.log("I did catch: ", err.message));

由于我对错误应该如何“冒泡”的理解,我希望控制台记录如下:

I did catch: Rejecting Big

但事实并非如此。相反,控制台显示 Uncaught Error :

Uncaught (in promise) Error: Rejecting Big

如果我在 DoublePromiser 中的链的末尾添加一个 catch,我只会得到我期望(和想要)的东西,如下所示:

    function DoublePromiser(str1, str2, doResolve) {
        this.promise = new Promise((resolve, reject) => {
            promiseString(str1, 100, doResolve)
                .then((s1) => promiseString(s1 + str2, 100, doResolve))
                .then((s2) => resolve(s2))
                .catch((err) => reject(err)); // ADDING THIS TO MAKE IT WORK
        });
    }

现在我得到了我所期望的,错误并没有被捕获。但这似乎与错误冒泡的整个想法背道而驰,而且捕获错误只是为了重新拒绝相同的错误似乎很奇怪。

我是不是缺少一种让它简单工作的方法?

我是否遗漏了一些基本概念?

最佳答案

您正在使用 promise 构造函数反模式。不要将现有的 promise 包装在您自己做出的另一个 promise 中,因为这只会让您做很多额外的工作以使事情正常工作,而且由于大多数人没有正确地做这些额外的工作,它也很容易出现编程错误。只需返回您已经拥有的 promise 即可。

改变这个:

function DoublePromiser(str1, str2, doResolve) {
    this.promise = new Promise((resolve, reject) => {
        promiseString(str1, 100, doResolve)
            .then((s1) => promiseString(s1 + str2, 100, doResolve))
            .then((s2) => resolve(s2))
            .catch((err) => reject(err)); // ADDING THIS TO MAKE IT WORK
    });
}

为此:

function DoublePromiser(str1, str2, doResolve) {
    return promiseString(str1, 100, doResolve)
       .then((s1) => promiseString(s1 + str2, 100, doResolve));
}

然后将其作为函数使用:

DoublePromiser("Big", "Promise", false).then(...);

回顾:您几乎总是希望从 .then() 处理程序中返回内部 promise ,因为这允许嵌套错误向上传播,并且还可以适本地链接/排序异步操作.

而且,您几乎总是希望避免围绕现有 promise 包装新 promise ,因为您可以链接和/或返回您已有的现有 promise 。

此外,请注意,如果您执行 .catch(),它将“处理”一个被拒绝的 promise 并返回一个新的未被拒绝的 promise ,从那里继续 promise 链,除非在.catch() 处理程序返回一个被拒绝的 promise 或抛出一个异常。所以,这:

p.catch((err) => console.log(err)).then(() => console.log("chain continues"))

将愉快地执行两个 console.log() 语句,因为 .catch()“处理”了 promise ,因此 promise 链愉快地继续。


正如我在之前的评论中所说,如果没有 20 页的关于 promises 如何工作的教程,这些 100% 的理论讨论很难准确地达到您真正想要完成的目标(我们必须猜测真正的问题是什么)很多东西。如果您发布一个您尝试使用此技术解决的真实问题,那就更好了,我们可以通过几行代码和几段解释来展示/解释最好的方法。

关于javascript - ES6 Promise 错误没有按预期冒泡,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38625209/

相关文章:

c - 处理从库中的 OS API 返回的错误的最佳方法是什么?

javascript - 为最大值(value)添加类

python - Selenium 文件错误,我无法正确导入它们

javascript - 使用 HTML 和 Phonegap 设置移动应用程序的大小

java - com.kami2017.app.MainActivity.onCreate上的Android Studio错误

javascript - Angular 4 需要导入 Promise

javascript - Mongoose 和 Node 查询的时机

jquery - 将变量传递给 $.ajax().done()

javascript - rxjs 将来自 2 个不同可观察量的 2 个对象组合在一起

javascript - 在 jQuery 中获取数据而不是重复使用 parent() 和 next() 的替代方法?