防止出现“未捕获(承诺)”警告。如何避免“抓”块? ES6承诺与Q承诺

时间:2018-11-27 17:34:51

标签: javascript ecmascript-6 promise es6-promise 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

...否则,我将在控制台中收到“未捕获(承诺)”警告。因此,我不知道在使用.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/js-xqwiq1?file=index.js

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

第2部分

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

观看此演示https://stackblitz.com/edit/js-g6efg5

在此页面https://promisesaplus.com/implementations中,我发现Q库是Promises / A +规范的实现。但是为什么会有不同的行为呢? es6承诺遵守Promises / A +规范吗?

谁能解释为什么这些库具有不同的行为,哪一个是正确的,以及在“ ES6 Promises实现”正确的情况下如何实现所提到的逻辑?

1 个答案:

答案 0 :(得分:1)

  

我发现我被迫在各处使用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"));

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

Node.js在process对象上也支持此功能:

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实现”正确的情况下如何实现所提到的逻辑?

两个都是正确的。完全不可能在用户区(库所在的地方)报告未处理的异常,这样就不会出现误报。 JavaScript引擎可以将其作为垃圾回收的一部分来进行处理(例如:如果不再有任何对诺言的引用,并且诺言被拒绝,并且没有人处理该诺言,则发出警告)。