【问题标题】:Using generators to pause until promise resolves使用生成器暂停直到 promise 解决
【发布时间】:2016-09-18 21:48:07
【问题描述】:

我在 node.js 中有一个批处理作业: 将文件复制到目录中,对文件进行分析,然后删除文件。

我想遍历一组作业并使用生成器暂停执行,直到该批处理作业完成,然后再开始另一个作业。这是我目前所拥有的:

const cars = ["toyota", "honda", "acura"];

function copyFilesAndRunAnalysis(car) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() { // simulate some delay
      resolve(); // control should return to generator here
    }, 1000);
  });
}

function* doCar(car) {
  yield copyFilesAndRunAnalysis(car);
}

// BEGIN HERE
console.log('start here');
carBatch = doCar(cars[0]);
carBatch.next(); // confusion here!!!
carBatch.next(); // should this all be in a forEach loop?

我想做的是有一个循环遍历每辆车的 forEach,在 copyFilesAndRunAnalysis 方法中完成所有相应的工作——暂停到 Promise.resolve() 然后继续下一个。尝试 forEach 根本不会运行任何东西。

【问题讨论】:

  • 不确定是否可以使用生成器来执行此操作。生成器不是为处理异步操作而设计的。可观察对象的概念涵盖了您想要做的事情。 Observables 现在在 ES7 命题中。
  • 生成器只是同步迭代器的工厂。您必须将它们与 Promise 或 observable 结合起来以处理异步代码。请注意,Promise 只能发出一个值/原因,而生成器能够随着时间的推移发出许多值。有关该主题的更多信息,请访问medium
  • 查看What happens when promise is yielded in javascript?ECMA6 generators: yield promiseUnderstanding code flow with yield/generators 以找到您所缺少的:异步运行生成器的驱动程序。他们不会自己这样做。

标签: javascript node.js ecmascript-6 generator es6-promise


【解决方案1】:

您不要在问题中使用.value js。由Generator 产生的next() 对象的.value 将是从copyFilesAndRunAnalysis 返回的Promise,其中.then() 可以链接到.next().value()Array.prototype.shift() 可以用于递归调用@987654331 @ 直到没有项目保留在 cars 数组的原始或副本中。

const cars = ["toyota", "honda", "acura"];
let carsCopy = cars.slice(0);

function copyFilesAndRunAnalysis(car) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() { // simulate some delay
      resolve(car); // control should return to generator here
    }, 1000);
  })
}

function* doCar(cars) {
  yield copyFilesAndRunAnalysis(cars);
}

// BEGIN HERE
console.log("start here");
carBatch = doCar(carsCopy.shift());
carBatch.next().value.then(function re(data) {
  console.log(data);
  return carsCopy.length 
         ? doCar(carsCopy.shift()).next().value.then(re) 
         : "complete"
})
.then(function(complete) {
  console.log(complete); 
})

注意,使用Promise,递归可以实现相同的过程;不使用Generator 函数。

const cars = ["toyota", "honda", "acura"];
let carsCopy = cars.slice(0);

function copyFilesAndRunAnalysis(car) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() { // simulate some delay
      resolve(car); // control should return to generator here
    }, 1000);
  })
}

// BEGIN HERE
console.log("start here");
carBatch = copyFilesAndRunAnalysis(carsCopy.shift());
carBatch.then(function re(data) {
  console.log(data);
  return carsCopy.length 
         ? copyFilesAndRunAnalysis(carsCopy.shift()).then(re) 
         : "complete"
})
// do stuff when all items within `cars` have been 
// processed through `copyFilesAndRunAnalysis`
.then(function(complete) {
  console.log(complete); 
})

【讨论】:

    【解决方案2】:

    ES6 生成器与异步执行没有任何关系。它们提供了在第三方代码(特别是co)中实现异步控制流的可用机制。

    可以这样使用

    co(function* () {
        console.log('start here');
    
        for (let car of cars) {
            yield copyFilesAndRunAnalysis(car);
        }
    
        console.log('end here');
    });
    

    co 将包装好的生成器函数转换为一个承诺并且不会创造奇迹。所有异步操作都应该在生成器函数中执行。

    【讨论】:

      猜你喜欢
      • 2015-09-05
      • 2013-12-04
      • 2021-08-19
      • 2021-05-01
      • 2011-10-23
      • 2015-02-07
      • 2018-12-19
      • 2014-09-02
      • 1970-01-01
      相关资源
      最近更新 更多