处理承诺库中的简单值拒绝

Handling simple value rejects in a promise library

Bluebird 模块检测到非 Error 拒绝时,它会报告 Warning: a promise was rejected with a non-error

那么我们在写一个可重用的promise库的时候,如果是客户端的代码抛出了简单的值,我们应该怎么处理呢?

简单my-library示例:

var Promise = require('bluebird');

module.exports = function (cb) {
    return new Promise(function (resolve, reject) {
        try {
            cb();
            resolve('some data');
        } catch (e) {

            // should we do this?
            reject(e);

            // or should we do this?
            // reject(e instanceof Error ? e : new Error(e));
        }
    });
};

使用它的客户端:

var lib = require('my-library');

lib(function () {
    throw 'Regular text';
})
    .catch(function (error) {
        // - should we expect exactly 'Regular text' here?
        // - or should it be wrapped into Error by the promise library?
    });

在上面的示例中,我们将再次看到相同的 Warning: a promise was rejected with a non-error,在这种情况下,这显然是客户端的错误,但问题是 - 它将针对执行拒绝的 promise 库进行报告.

这带来了可重用库应如何处理此类情况的问题。

我正在寻找一般推荐。

还要考虑到有时客户端可能是您试图包装到 promise 中的旧库。

你应该绝对客观地用错误包装非错误。

非错误对于调试来说是可怕的,蓝鸟警告在那里是因为如果它是原始的,非常很难找出错误的来源。您不能将属性附加到基元,并且它们没有堆栈跟踪。

堆栈跟踪意味着您不必猜测错误的来源 - 您知道的。

也就是说,bluebird 已经使用 promisifypromisifyAll 自动执行此操作并考虑使用它们。如果您手动执行此操作 - 只需确保您 throwreject 也有堆栈。

Node 还会查找您未处理的拒绝的堆栈跟踪 - 因此拒绝垃圾不仅会给您在 Node 中无用的信息,而且实际上可能会使您的程序崩溃。

错误消息应该包含在错误对象中,而不是自动

自动换行会降低堆栈跟踪的有用性。例如,假设客户端函数是 f 而你的库函数是 g:

function f(x) { throw 'Hello world' }
function g(f, x) { try { f(x); } catch (e) { throw new Error(e); } }

g(f, 1)

发生错误的客户端函数和行号将从堆栈中完全丢失:

Error: Hello world
    at g (repl:1:52)
    at repl:1:1

而如果客户端函数创建错误对象:

function f(x) { throw new Error('Hello world'); }
function g(f, x) { try{ f(x); } catch (e) { throw e; } }

g(f, 1)

我们得到完整的堆栈跟踪:

Error: Hello world
    at f (repl:1:23)
    at g (repl:1:25)
    at repl:1:1

无法将堆栈恢复到您的库中的点,这对用户来说毫无用处(他们将无法调试自己的代码)。

就是说,这在很大程度上取决于您制作的库类型以及您希望它向用户呈现的合同类型。在使用用户传递的回调之前,您应该仔细考虑,因为它们颠倒了堆栈中的正常责任链。

Promises 使这更容易,因为它们取消了反转:首先调用库以生成 promise,然后该 promise 被传递给回调。因此,在创建 promise 的同时创建一个新错误允许 Bluebird 至少部分地查看/扩充客户端代码的堆栈(创建 promise 的行将出现在堆栈中)。警告仍然存在,因为无法提供完整的堆栈。

不,他们只是希望您将 JSON 错误对象包装成某种东西。

这不是自由,这是独裁。

用庞大的错误包装器包装简单的 JSON 对象毫无意义。

别听他们的。