你如何同时映射发电机结果?

时间:2015-09-15 01:09:58

标签: javascript ecmascript-6

如何同时在生成器中映射异步调用的结果?

var generator = (function *() {
  var lotsOfThings = yield asyncTask.call(generator);

  var mappedResults = yield lotsOfThings.map(thing => {
    // fails with a syntax error unless you do a `for…of` loop, but also doesn’t run concurrently regardless
    return (yield asyncTask.call(generator, thing));
  });

  // then do something with mappedResults
})();

generator.next();

function asyncTask(…query) {
  somethingAsync(…query, (err, res) => this.next(res));
}

此外,即使在常规for...of循环中,也无法同时运行每个asyncTaskyield将导致每个任务之间的暂停,实质上是发出同步AJAX请求。理想情况下,你希望它像承诺一样工作,就像这个范例:

// these tasks will run concurrently (unlike the above example)
let promises = someThings.map(thing => {
  return new Promise((resolve, reject) => {
    somethingAsync((err, res) => {
      resolve(res);
    });
  });
});

Promise.all(promises).then(/* do stuff */);

promise方法可能会导致所有嵌套的毛病,但好处是异步任务可以同时运行...而生成器看起来不错,但循环任务不是并发的。有什么想法吗?

2 个答案:

答案 0 :(得分:1)

我试图在没有第三方库的情况下绘制类似的东西:

// Async runner
function async(generator){
  var process = function(result){       
    if (result.done) {
      return;
    }
    (Array.isArray(result.value) ? Promise.all(result.value) : result.value).then(function(value){
      process(sequence.next(value));
    });
  };

  var sequence = generator();
  var next = sequence.next();
  process(next);
};

// Generator function
var generator = function* () {
  var list = yield getList();
  console.log(list); // outputs [1, 2, 3, 4, 5]

  var details = yield list.map(p => getDetails(p));    
  console.log(details); // outputs [11, 12, 13, 14, 15]
}

// Your async requests go here
function fakeAsync(f) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      f(resolve);
    }, 500);
  });
}

function getList() {
  return fakeAsync(function(resolve) {
    resolve([1, 2, 3, 4, 5]);                  
  });
}

function getDetails(i) {
  return fakeAsync(function(resolve) {
    resolve(i + 10);                  
  });
}

async(generator);

这是你想要实现的目标吗?

答案 1 :(得分:0)

我正在寻找的答案可以通过co来实现。

<property name ="Web Application" value="\Fxnet2\Web\webpl\" />
<property name="Web Service" value="\FXnet2\Web\FXnet_SC_WS\" />

修改:已将co(function* () { // maybe we need a token from our API before we can do anything let token = yield new Promise((resolve, reject) { getToken(token => resolve(token)); }); // these run in parallel var queries = yield [ request('/route', token), request('/another-route', token) ]; // [[], []] becomes [...] return _.flatten(queries); }); // our async request function returns a promise function request(route, token) { return new Promise((resolve, reject) => { somethingAsync(route, token, (res) => { resolve(res); }); }); } 更改为somethingAsync,因为在我的实际案例中,它已调用尚未返回的第三方API一个承诺。