如何避免在promise回调中包装代码?

lau*_*ent 3 javascript design-patterns callback promise

为了不在promise回调中包装代码块(以保存一个级别的缩进),我有时会执行以下操作:

function myFunction() {
    // Create the promise object and get the "resolve" callback
    let promiseResolve = null;
    const promise = new Promise((resolve, reject) => {
        promiseResolve = resolve;
    });

    // Then later in the code:
    setTimeout(() => {
        // Something slow
        promiseResolve();
    }, 1000);

    // And at the end
    return promise
}
Run Code Online (Sandbox Code Playgroud)

它有效,但感觉有点凌乱.在JavaScript中有没有适当的模式?

jfr*_*d00 9

在JavaScript中有没有适当的模式?

是的,正确的模式是你显然要避免的.

function myFunction(data) {
    return new Promise((resolve, reject) => {
        // put code in here that calls resolve() or reject()
        someAsyncOperation(data, function(err, result) {
            if (err) {
                reject(err);
            } else {
                resolve(result);
            }
        });
    });
}
Run Code Online (Sandbox Code Playgroud)

对于您正在展示的内容,实际上没有理由将执行器函数的范围外的resolve()reject()处理程序分配.

以下是将代码保存在Promise执行程序中的一些好处:

  1. 它是自动投掷安全的.如果你在执行函数内部(意外地)同步抛出,它将自动被捕获并变成对该承诺的拒绝.
  2. 如果你在promise执行函数之外的代码中同步抛出,它将不会被捕获,你的函数将同步抛出.返回一个promise并同步抛出是非常糟糕的,因为这给调用者带来了很多负担,需要在两个独立的机制中观察错误.
  3. 您没有说明为什么要为代码添加复杂功能,以避免将某些代码放在您已经拥有的缩进级别.
  4. 承诺执行者是出于这个原因设计的,原因很多.您所显示的偏好本质上是"延迟"模型,您可以在其中创建一个可以传递的对象,该对象具有用于解析或拒绝的公开方法.这不是承诺的设计中心,并且非常好地思考为什么它不是他们决定去的方式.我会看看我是否可以找到一些辩论和讨论参考,但我知道我已经看过他们,他们对我有意义.
  5. 对于类似延迟的接口,非常非常偶尔会有一些基本原理,其中使用该模型的代码非常简单.您可以使用promise executor创建自己的Deferred对象(这几乎就是您在这里尝试做的事情),但实际上只有在已经证实需要它时才能完成,而不仅仅是因为您更喜欢编码风格或者想要避免将代码放入执行程序回调中.
  6. 你在这里有很多代表,所以我猜你是一个相当有经验的人,所以我很惊讶你拒绝将代码放在执行者中,因为Javascript鼓励这很多.这是一种非常常见的风格(在这些回调中使用匿名回调和嵌入代码逻辑).甚至承诺.then().catch()要求.要使用Javascript编程,必须使用它并期望它.通常还需要访问父范围变量.
  7. 通常,您不希望在同一逻辑流中混合回调和承诺代码.因此,当我想使用带有非基于承诺的回调接口的promise接口时,我要做的第一件事就是尽可能在最低级别为回调接口创建一个promisified接口,这样我就可以完全使用该接口接口.在大多数情况下,我使用一个自动化的方式来promisify接口如util.promisify()蓝鸟的Promise.promisifyAll().然后,我的逻辑流程完全是基于基于promise的操作,我甚至从未面对你展示的代码类型,任何编写这样的代码的诱惑也都消失了.

一些参考:

为什么Promise构造函数需要执行程序?

延期反模式

揭示构造函数模式

Promise.defer的正确模式是什么?


如果您确实发现您认为"需要"Deferred对象,那么我建议您将该功能封装在一个新对象中并使用它,而不是每次使用它时手动编码.在我的所有编码中,我只发现代码使用Deferred对象更容易编写和更清洁,这是一个非常不寻常的低级别队列系统,可以管理一堆不同的任务.

有几个简单,简短的代码片段来实现Deferred对象.这是一个:

为什么Promise构造函数需要执行程序?