可以(应该)JavaScript 承诺用于 co-dependent 功能吗?

Can (should) JavaScript promises be used for co-dependent functions?

Promises 非常适合将某些内容附加到异步调用的 end,而异步调用不需要知道其追随者。 promises 是否可以用于更一般或更复杂的情况,即在异步调用过程中需要回调,如果可以,它能否提供相同级别的分离?

例如,假设您有两个函数 a 和 b,其中执行顺序从 a 转移到 b 并返回两次。

使用回调:

function a() {
    console.log('a1');
    b(function(b2) { 
        requestAnimationFrame(function() { 
            console.log('a2'); 
            b2(); 
        }); 
    });
}

function b(a2) {
    console.log('b1');
    a2(function() { 
        requestAnimationFrame(function() { 
            console.log('b2'); 
        }); 
    });
}

我知道这两个函数可以分别分成两部分并用 promise 串在一起,但这可能会丢失 a1/b1 中重要的 expensive-to-compute 范围变量设置,或者导致冗余代码甚至更难遵循执行顺序。

问题是,是否可以使用 promise 重写这段代码,使 b() 不需要知道 a(),但确实为调用者提供了插入某些东西的机会 before b() 执行完毕?

在回答之前,我稍微修改了您的示例以突出显示执行流程:

function a() {
    console.log('a1');
    var c = function(b2) { 
        var d = function() { 
            console.log('a2'); 
            b2(); 
        });
        requestAnimationFrame(d);
    }
    b(c);
}

function b(a2) {
    console.log('b1');
    var e = function() { 
        var f = function() { 
            console.log('b2'); 
        });
        requestAnimationFrame(f);
    }
    a2(e);
}

这是相同的代码,只是我将四个匿名函数命名为 cdef,因为我想参考他们。

执行顺序如下:

  1. a被称为
  2. a 同步调用 b
  3. b 同步调用 c
  4. c 调用 requestAnimationFrame(异步 API)
  5. requestAnimationFrame returns
  6. c returns
  7. b returns 并完成执行
  8. a returns 执行完毕。

稍后,当动画帧可用时,会发生这种情况:

  1. d被称为
  2. d 同步调用 e
  3. e 呼叫 requestAnimationFrame
  4. 等等

当然 e 可以访问 b 中定义的变量,由于 JavaScript 闭包,这些变量比原始 b 的执行时间更长。

同样,在 JavaScript 中,我们将 a 视为一个异步操作,一旦 a 启动的所有内容都已完成,它就会结束,但只有两个异步步骤(4 和 11)在其中,所以这两个将从承诺中受益。

现在回答您的问题:在 b 不知道 a 的情况下,promises 能否提供相同的结果和分离?是的,但它不会与您的示例进行公平比较,因为它会在不需要时将您的同步调用增加为异步:

function a() {
    console.log('a1');
    var b2;
    b().then(function(result) {
        b2 = result;
        return new Promise(function(r) { requestAnimationFrame(r); })
    }).then(function() { 
        console.log('a2'); 
        return b2();
    }).catch(function(e) {
        console.log(e.message); // error-handling
    });
}

function b() {
    console.log('b1');
    return Promise.resolve(function() {
        return new Promise(function(r) {
            requestAnimationFrame(r);
        }).then(function() { 
            console.log('b2'); 
        });
    });
}

这里的技巧是b returns步在a后面执行,这是一个可以重复的模式。

这个模式好吗?如果不了解更多关于原始用例的信息,很难说。对于异步调用,我还没有遇到没有从 promises 中受益的调用,但是对于同步调用,我不会,因为它会改变执行顺序(除非可能只有一个异常值,而其他所有异常值都是异步的,这有助于提高可读性) .