【问题标题】:Promise nesting vs chaining stylePromise 嵌套 vs 链式
【发布时间】:2017-04-19 06:15:04
【问题描述】:

Promise 新手;考虑存在promiseA()promiseB(a) 的情况,这取决于第一个结果,我想从两者收集结果并执行第三个操作doSomething(a, b)

样式 A(闭合/嵌套)

promiseA().then(function (resultA) {
  return (promiseB(resultA).then(function (resultB) {
    doSomething(resultA, resultB);
  }));
});

样式 B(返回值/链接)

promiseA().then(function (resultA) {
  return Promise.all([resultA, promiseB(resultA)]);
}).spread(function (resultA, resultB) {
  doSomething(resultA, resultB);
});

据我所知,这些是等价的:

  • promiseApromiseB 之间的排序约束相同
  • 最终承诺返回undefined
  • 如果promiseApromiseB 被拒绝,或doSomething 抛出,则最终承诺将被拒绝。

就风格而言,风格 B 减少了缩进(厄运金字塔)。

但是,样式 B 更难重构。如果我需要引入中间的promiseA2(a)doSomething(a, a2, b),我需要修改 3 行(Promise.allspreaddoSomething),这可能会导致错误(意外交换等),而使用 Style A I仅修改 1 行 (doSomething) 并且变量名称清楚地表明它是哪个结果。在大型项目中,这可能很重要。

这两种风格之间是否还有其他非功能性的权衡?一个与另一个的更多/更少的内存分配?更多/更少的事件循环?更好/更差的异常堆栈跟踪?

【问题讨论】:

标签: javascript scope promise


【解决方案1】:

我认为这两种方法之间的非功能性权衡并不那么重要:第二种方法在创建数组和传播相应结果方面有一些开销,它会创建一个更多的承诺。然而,在异步流程中,我认为所有这些都可以忽略不计。

您主要关心的似乎是重构的难易程度。

为此,我建议使用一组函数,并在其上使用reduce

[promiseA, promiseB, doSomething].reduce( (prom, f) =>
    prom.then( (res = []) => ( f(...res) || prom).then( [].concat.bind(res) ) )
, Promise.resolve() );


// Sample functions
function wait(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

function promiseA() {
    console.log('promiseA()');
    return wait(500).then(_ => 13);
}

function promiseB(a) {
    console.log('promiseB(' + a + ')');
    return wait(500).then(_ => a + 2);
}

function doSomething(a, b) {
    console.log('doSomething(' + a + ',' + b + ')');
}

这个想法是then 回调链中的下一个函数获取作为参数传递的所有先前结果。因此,如果您想在链中注入一个返回承诺的函数,只需将其插入数组即可。尽管如此,您仍需要注意传递的参数:它们在此解决方案中是累积的,因此doSomething 不是规则的例外。

另一方面,如果您只希望doSomething 获取所有结果,并且只将最近的结果传递给每个中间函数,那么代码将如下所示:

[promiseA, promiseB].reduce( (prom, f) =>
    prom.then( (res = []) => f(...res.slice(-1)).then( [].concat.bind(res) ) )
, Promise.resolve() ).then(res => doSomething(...res));

function wait(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

function promiseA() {
    console.log('promiseA()');
    return wait(100).then(_ => 13);
}

function promiseB(a) {
    console.log('promiseB(' + a + ')');
    return wait(100).then(_ => a + 2);
}

function doSomething(a, b) {
    console.log('doSomething(' + a + ',' + b + ')');
}

【讨论】:

    猜你喜欢
    • 2023-03-12
    • 2022-06-21
    • 2018-10-01
    • 1970-01-01
    • 2014-07-09
    • 2016-07-26
    • 1970-01-01
    • 1970-01-01
    • 2017-04-03
    相关资源
    最近更新 更多