首页 > 解决方案 > 防止“未捕获(承诺)”警告。如何避免'catch'块?ES6 承诺与 Q 承诺

问题描述

我的问题包括两部分:

第1部分

根据标准 ES6 Promise,我看到我被迫在catch任何地方使用块,但它看起来像复制/粘贴并且看起来很奇怪。

例子:

我有一些类向后端发出请求(我们称之为API类)。

我对API课堂使用有一些要求:

1)我需要在我的应用程序的不同部分发出请求,处理单个请求错误:

// somewhere...
api.getUser().then(... some logic ...);

// somewhere in another module and in another part of app...
api.getUser().then(... some another logic...); 

2)我希望'then' 块仅在'getUsers' 成功时才起作用。

3)我不想catch在我使用的任何地方写块api.getUsers()

api.getUser()
// I don't want following
.catch(e => {
    showAlert('request failed');
})

所以我试图在类内为所有“用户请求”实现单一错误处理

class API {
    getUser() {
        let promise = makeRequestToGetUser();
        promise.catch(e => {
            showAlert('request failed');
        });
        return promise;
    }
}

...但如果请求失败,我仍然被迫使用catch

api.getUser()
    .then(... some logic...)
    .catch(() => {}) // <- I forced to write it to avoid of “Uncaught (in promise)” warning

...否则我会在控制台中收到“Uncaught (in promise)”警告。所以我不知道如何在我使用实例的.catch任何地方避免阻塞的方式。api

似乎这来自在这样的代码中抛出错误:

// This cause "Uncaught error"
Promise.reject('some value').then(() => {});

也许你可以说'只是回到你的班级'抓住'承诺'。

class API {
    getUser() {
        return makeRequestToGetUser().catch(e => {
            showAlert('request failed');
            return ... 
        });
    }
}

...但这与我的#2要求相矛盾。

请参阅此演示:https ://stackblitz.com/edit/promises-catch-block-question

所以我的第一个问题是如何实现所描述的逻辑而不在我使用调用的catch任何地方编写块?api

第2部分

我检查了API与库相同的类实现是否Q会得到相同的结果,并且很惊讶,因为我没有得到“Uncaught (in promise)” warning. 顺便说一句,它比原生 ES6 Promises 的行为更值得期待。

在此页面https://promisesaplus.com/implementations我发现该Q库是 Promises/A+ 规范的实现。但是为什么它有不同的行为呢?es6 promise 是否尊重 Promises/A+ 规范?

谁能解释为什么这些库有不同的行为,哪个是正确的,以及如果“ES6 Promises implementation”正确,如何实现上述逻辑?

标签: javascriptecmascript-6promisees6-promiseq

解决方案


我看到我被迫到处使用 catch 块

不,你不需要这样做。相反,将由创建的承诺返回then给调用者(以及该调用者的调用者,并且......)。在可用的最高级别处理错误(例如,启动调用序列的事件处理程序)。

如果这对您来说仍然太多catch,您可以挂钩unhandledrejection事件并阻止其默认值:

window.addEventListener('unhandledrejection', event => {
    event.preventDefault();
    // You can use `event.reason` here for the rejection reason, and
    // `event.promise` for the promise that was rejected
    console.log(`Suppressed the rejection '${event.reason.message}'`);
});

Promise.reject(new Error("Something went wrong"));

浏览器将在控制台中报告未处理的拒绝之前触发该事件。

processNode.js 在对象上也支持这一点:

process.on('unhandledRejection', error => {
  // `error` is the rejection reason
});

请注意,您可以直接获取原因,而不是作为事件对象的属性。

所以我不知道如何在我使用实例的.catch任何地方避免阻塞的方式。api

当然getUser需要知道它的调用者失败了?我的意思是,如果答案真的是“不,他们没有”,那么事件就是要走的路,但实际上使用的代码api应该如下所示:

function useTheAPI() {
    return getUser()
        .then(user => {
            // Do something with user
        });
}

(或async等价物)以便代码调用useTheAPI知道发生了错误;同样,只有顶层需要实际处理错误。

谁能解释为什么这些库有不同的行为,哪个是正确的,以及如果“ES6 Promises implementation”正确,如何实现上述逻辑?

两者都是正确的。完全在用户区(图书馆所在的地方)报告未处理的异常很难做到没有误报。JavaScript 引擎可以将其作为其垃圾收集的一部分来执行(例如:如果没有任何东西对 promise 的引用,并且它被拒绝,并且没有任何处理该拒绝,则发出警告)。


推荐阅读