【问题标题】:Running promises sequentially: each promise starts after the previous one ends按顺序运行 Promise:每个 Promise 在前一个 Promise 结束后开始
【发布时间】:2017-11-16 06:26:03
【问题描述】:

这个问题有很多答案,但大部分都是同步promise的解析(即执行结束,而不是执行开始)。

This solution 假设我们已经有一个函数数组:

var funcs = [foo, bar, baz, qux];

如何在不执行函数的情况下创建这样的数组?我试过这个:

var promises = [];
for (i = 0 ; i < 3, ++i){
    promises.push( someFunction(i) )
}

function someFunction(i) {
    return new Promise((resolve, reject) => {
        console.log(i);
        resolve(i);
    });
}

在 for 循环结束时,promises 数组被填充,但 someFunction 已经执行了 4 次。使用Promise.allQ 序列只是序列解析。

如何才能真正实现这些功能的开头同步?特别是:

foo().then(bar).then(baz).then(qux);

----------------------------------------------- -----------------

更新(使用异步函数的简单解决方案): 执行此操作的简单方法是使用async 函数和await。请参阅 this answer 以了解在循环中调用 Promise 的示例,其中每个 Promise 将在前一个 Promise 解决时被调用。

【问题讨论】:

  • 我不认为内置的 promise API 有这个功能。你可以试试 bluebird 的 Promise.reduce:bluebirdjs.com/docs/api/promise.reduce.html
  • @KarelG:正是我的问题!如何在不调用它的情况下将其推入数组?我想在 for 循环中动态创建这些承诺。
  • for (let i = 0 ; i &lt; 3, ++i){ funcs.push(() =&gt; someFunction(i)) } 可以。
  • @Bergi:我认为这不会连续运行它们,等待前一个解决。

标签: javascript node.js promise q es6-promise


【解决方案1】:

你只需要传递函数的名字,不需要传递参数。 在您的示例中,您调用

      someFunction(i) 

- 你传递参数 i,所以这是一个函数调用。 您应该仅按其名称推送功能。每个函数的参数都是在前一个 promise 中解析的值。

function someFunction(i) {
    return new Promise((resolve, reject) => {
        console.log(i);
       resolve(i+1); // increase the value here
   });
}

通过这种方式,参数将被传递给下一个增加1的函数。但是对于链中的第一个函数,您应该传递参数。 类似的东西

 someFunction(0).then(someFunction).then(someFunction)

(在此解决方案中,您不需要数组。)

【讨论】:

  • 那以后如何才能正确的依次调用这些函数呢?
  • @Ari 你想让同一个函数执行 3 次?
  • 是的,使用不同的参数。
  • @Ari 链中的每个函数都应该负责通过解析值将参数传递给下一个函数。您可以使用要开始的参数调用第一个。查看我的编辑
【解决方案2】:

问题是

promises.push( someFunction(i) )

当您填充promises 数组时,每次都会调用someFunction,然后将其值传递给.push 方法。所以它会根据需要提前执行。

解决方法是不调用它。这并不容易实现,所以我在想一点(但丑陋的)hack。我引入了一个对象{p: ..., val: ...},它包含一个promise 函数和该promise 函数的值。如果要提供多个值,只需传递一个数组。 apply() 方法会将其转换为您的函数参数。函数callPromise 以正确的方式处理函数的执行。

可能有人想出了更好的解决方案,但这是我能很快想到的。

下面是一个按顺序调用 Promise 的示例。我添加了一个额外的函数(如果你有另一个函数有多个参数)作为 PoC。

var promises = [];
for (let i = 0 ; i < 3; ++i){
    promises.push( {p: someFunction, val: i} );
}

promises.push({p: anotherFunction, val: [100,33]});
promises.push( {p: someFunction, val: 4} );

function someFunction(i) {
    return new Promise((resolve, reject) => {
        console.log('someFunction, i: ' + i);
        resolve(i);
    });
}

function anotherFunction(i1, i2) {
    return new Promise((resolve, reject) => {
        console.log('anotherFunction, i1: ' + i1 + ', i2: ' + i2);
        resolve(i);
    });
}


function callPromise(prom) {
    if(Object.prototype.toString.call(prom.val) !== '[object Array]') prom.val = [prom.val];
    return prom.p.apply(null, prom.val);
}

console.log('before loop');
let result = callPromise(promises[0]);
for (let i = 1 ; i < promises.length; ++i) {
  result = result.then(callPromise(promises[i]));
}

【讨论】:

  • 你能解释一下 callPromise 到底在做什么吗?
  • @Ari prom{p: ..., val: ...} 对象。它首先检查 val 是否是一个数组。如果没有,请将其设为数组。然后它使用.apply 运行带有val 数组的函数p。如果您查看它的文档,您会发现该数组是作为函数 p 的参数提供的。该函数返回一个承诺,然后可以像承诺一样处理:.then.catch 等 ...
猜你喜欢
  • 1970-01-01
  • 2019-07-05
  • 2018-07-12
  • 2016-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-27
  • 1970-01-01
相关资源
最近更新 更多