向 nodejs 中的承诺数组添加延迟或睡眠

spa*_*kus 1 javascript callback node.js promise async-await

我有一个一直在努力解决的承诺链问题。我调用一个外部 api,它返回我需要处理的数据并将其摄取到 mongo 数据库中。我正在将 nodejs 和 mongodb 与 express 一起使用。无论如何,对 api 的调用工作正常,问题是我正在同时制作大量的调用。我想放慢他们的速度,就像为一组打所有电话一样。等一下。为下一组发出所有呼叫。如果这是已知数量的集合,我会承诺将它们链接起来。我不知道有多少套,所以我在循环它们。我认为关闭是问题,但无法解决它。到示例代码!

  function readApi(carFactory){
    var promise = new Promise(function(resolve, reject) {
      // call out to api, get set of car data from factory1

      console.log(carFactory);
      if (true) {
        console.log('resolved');
        resolve("Stuff worked!"+carFactory);
      }
      else {
        reject(Error("It broke"));
      }
    });
    return promise;
  }

  function manager(){

    //singular call
    readApi("this is a singular test").then(returnedThing=>{
      console.log(returnedThing); //Stuff worked! this is a singular test
    });

    let dynamicList = ["carFactory1", "carFactory2","carFactory3","carFactory..N"];
    let readApiAction = [];
    dynamicList.forEach(carIter=>{
      readApiAction.push(readApi(carIter));
    });
    //ok so now I got an array of promise objects.
    //I want to call the first one, wait 1 minute and then call the next one. 

    //originally I was calling promise.all, but there is no way to get at 
    //each promise to pause them out so this code is what I am looking to fix
    let results= Promise.all(readApiAction);
    results.then(data=>{
      data.forEach(resolvedData=>{
        console.log(resolvedData); //Stuff worked carFactory1, etc... 
      });      
    });


    //singular call with timeout, this does not work, each one called at the same time
    let readApiActionTimeouts = [];
    dynamicList.forEach(carIter=>{
      setTimeout(callingTimeout(carIter), 6000);
    });
  }

  //just a function to call the promise in a timeout
  //this fails with this  - TypeError: "callback" argument must be a function
  function callingTimeout(carIter){
    readApi(carIter).then(returnedThing=>{
      console.log("timeout version"+returnedThing);
    });
  }
Run Code Online (Sandbox Code Playgroud)

Szy*_*sza 5

有点理论。本机Promise.all只是组承诺。它们仍然是同时执行的(尽管以异步方式,就像所有 JS 代码一样,但彼此并行)。这意味着它仍然会拥塞 API 并执行大量调用。

另一件需要注意的是,如果你想延迟一个承诺,你必须延迟它的返回值(例如resolve)。为此,您可以使用 setTimeout INSIDE new Promise(请查看下面的更多说明)。

设置超时是异步的。它不像在其他语言中那样工作(它不仅仅是暂停执行)。在您的代码中设置固定超时只会导致将所有执行移动 6 秒。它们仍然并行发生(虽然在不同的滴答声中,但差异很小)。尝试例如为循环中的每个生成不同的超时 - 您会注意到它们发生在不同的时间但是!对于promisified code,这不是一个好的解决方案!

现在 - 是时候给出实际答案了!

如果您使用 Bluebird,它有一种特殊的方法可以为每个承诺添加延迟或超时。没有它,您将不得不围绕 Promise 编写一个包装器,例如在特定时间后解析它,然后将它与Promise.all.

第一个解决方案(蓝鸟):

function delayMyPromise(myPromise, myDelay);
  return Promise.delay(myDelay).then(function() {
    return myPromise;
  });
});
Run Code Online (Sandbox Code Playgroud)

然后在你的代码中:

return Promise.all(delayMyPromise(promise1, 1000), delayMyPromise(promise2, 2000)); // Notice different delays, you may generate them programatically
Run Code Online (Sandbox Code Playgroud)

或者更酷的是,您可以使用Promise.mapfrom Bluebird 而不是Promise.all它具有特殊的并发设置,因此您可以强制按特定顺序执行您的承诺,例如一次 2。这就是我在之前的项目中所做的:)

更多在这里:

纯原生 Promise 实现:

function delayMyPromise(myPromise, myDelay) {
  return new Promise(function (resolve, reject) {
    setTimeout(function() {
      return resolve(myPromise);
    }, myDelay);
  });
}
Run Code Online (Sandbox Code Playgroud)

但是,如果您不介意使用 Bluebird,我强烈推荐第一种方法。就像lodashPromises 一样,它真的很快 :)