javascript - 带有yield Promise.all()的生成器函数

标签 javascript asynchronous ecmascript-6 generator

我想分块运行一个函数,这样它将等待 10k 个 promise 解析然后继续,我使用以下生成器函数:

  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 已解决,它也永远不会从 yield 中返回。

是否可以使用生成器函数执行类似的操作?

编辑: 我想我想做的是实现类似 Bluebird 协程的东西:http://bluebirdjs.com/docs/api/promise.coroutine.html

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

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

最佳答案

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

因此生成器创建一个迭代器,它有 value和一个 bool 标志 done 。只要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');

在上面的代码片段中,它也通过一个 Promise 运行。因此,当整个队列结束时您会收到通知,它比原始片段要复杂一些,可以在here中找到。

可以在 MDN 上找到您所使用的模式的更容易理解的解释。

关于javascript - 带有yield Promise.all()的生成器函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43202432/

相关文章:

c# - Azure downloadtostreamasync 方法挂起

javascript - ES6 和 sequelize-cli

node.js - mongodb nodejs db.collection 不是函数

javascript - 为什么 JavaScript 等式前面带有 toFixed 加号?

javascript - 有没有办法防止 execCommand ("insertHTML") 删除 chrome 中的属性?

c# - 为什么 Task<TResult>.Result 在这种情况下不起作用?

javascript - Node promise 循环等待结果

javascript - 带有 Promise.all 的对象字面量(哈希)

javascript - 从基于 kotlin JVM 的项目调用 javascript 函数

javascript - date.Parse() 的问题