生成器Promise.all()的生成器函数

时间:2017-04-04 08:50:30

标签: javascript asynchronous ecmascript-6 generator

我想以块的形式运行一个函数,所以它会等待10k的promises来解析然后继续,我使用下面的生成器函数:

  function* processNodes(nodes, task){
    let i;
    let cnt = 0;
    let promiseArray = new Array(10000);
    let pInd = 0;
    let currId;

    for(i = 0; i<nodes.length; i++){
      currId = nodes[i];
      promiseArray[pInd++] = asyncFunc(currId, 0, task); // return a promise
      cnt++;

      if(cnt > 10000){
        console.log("going to yield", promiseArray)
        let pall = Promise.all(promiseArray);
        console.log("promise all", pall);
        yield pall;
        console.log("return from yield");  // never get here
        pInd = cnt = 0;
      }
    }
  }

但即使我看到pall已经解决,它也永远不会从收益中回归。

是否可以使用生成器功能执行此类操作?

编辑: 我想我要做的是实现像Bluebird的协程一样:http://bluebirdjs.com/docs/api/promise.coroutine.html

Edit2:这是我调用此函数的方式:

let x = processNodes(allNodes, someSimpleTask);
x.next();

1 个答案:

答案 0 :(得分:2)

您的问题是您不应该使用生成器功能。您永远不会到达console.log('return from field'),因为在yield处,代码在yield语句之后停止执行。只有当你再次调用迭代器时,它才会在yield语句之后继续(直到下一个yield语句)

因此,生成器创建一个迭代器,它具有value和bool标志done。只要完成没有设置为true,您就可以/应该再次调用下一个函数

您的代码的简化版本可以是以下

// a very basic async function, just outputting the argument each 5 ms
function asyncFunc(arg) {
  return new Promise(function(resolve) {
    setTimeout(() => {
      console.log(arg);
      resolve();
    }, 5);
  });
}

// the generator
function* generator(processNodes, task) {
  var limit = 4,
    queue = [];
  for (let i = 0; i < processNodes.length; i++) {
    queue.push(task(processNodes[i]));
    if (queue.length >= limit) {
      yield Promise.all(queue);
      // clears the queue after pushing
      console.log('after queue');
      queue = [];
    }
  }
  // make sure the receiver gets the full queue :)
  if (queue.length !== 0) {
    yield Promise.all(queue);
  }
}

function runThroughArguments(args, task) {
  return new Promise(function(resolve) {
    setTimeout(() => {
      var nodes = generator(args, task),
        iterator = nodes.next();

      if (!iterator.done) {
        // if it's not done, we have to recall the functionallity
        iterator.value.then(function q() {
          setTimeout(() => {
            iterator = nodes.next();
            if (!iterator.done && iterator.value) {
              // call the named function (in this case called q) which is this function after the promise.all([]) completed
              iterator.value.then(q);
            } else {
              // everything finished and all promises are through
              resolve();
            }
          }, 2);
        });
      } else {
        iterator.value.then(resolve);
      }
    }, 2);
  });
}

runThroughArguments(
  ['hey', 'you', 'the', 'rock', 'steady', 'crew'], 
  asyncFunc).then(() => console.log('completed'));

console.log('runs before everything');

在上面的代码片段中,它也会通过一个承诺。因此,当完整队列通过时,您可以得到通知,它比原始代码段复杂一点here

可以在MDN

上找到您正在使用的模式的更易于理解的解释