JavaScript异步编程:promises vs generator

sri*_*bin 49 javascript asynchronous node.js promise ecmascript-6

Promises和generator允许您编写异步代码.我不明白为什么这两种机制都是在ECMA脚本6中引入的.什么时候最好使用promises,什么时候生成器?

ale*_*ods 91

这两种技术之间没有对立.它们共存在一起很好地相互补充.Promise使您能够获得尚未提供的异步操作的结果.它解决了毁灭金字塔的问题.所以代替:

function ourImportantFunction(callback) {
  //... some code 1
  task1(function(val1) {
    //... some code 2
    task2(val1, function(val2) {
      //... some code 3
      task3(val2, callback);
    });
  });
}
Run Code Online (Sandbox Code Playgroud)

你可以写:

function ourImportantFunction() {
  return Promise.resolve()
    .then(function() {
        //... some code 1
        return task1(val3)
    })
    .then(function(val2) {
        //... some code 2
        return task2(val2)
    })
    .then(function(val2) {
        //... some code 3
        return task3(val2);
    });
}

ourImportantFunction().then(callback);
Run Code Online (Sandbox Code Playgroud)

但即使使用promises,您也​​必须以异步方式编写代码 - 您必须始终将回调传递给函数.编写异步代码比同步更难.即使有代码很大的承诺,也很难看到算法(嗯,这是非常主观的,有人可以与之争辩.但对于大多数程序员来说,我认为这是真的).所以我们想以同步方式编写异步代码.这就是发电机来帮助我们的地方.所以代替上面的代码你可以写:

var ourImportantFunction = spawn(function*() {
    //... some code 1
    var val1 = yield task1();
    //... some code 2
    var val2 = yield task2(val1);
    //... some code 3
    var val3 = yield task3(val2);

    return val3;
});

ourImportantFunction().then(callback);
Run Code Online (Sandbox Code Playgroud)

最简单的spawn实现可能是这样的:

function spawn(generator) {
  return function() {    
    var iter = generator.apply(this, arguments);

    return Promise.resolve().then(function onValue(lastValue){
      var result = iter.next(lastValue); 

      var done  = result.done;
      var value = result.value;

      if (done) return value; // generator done, resolve promise
      return Promise.resolve(value).then(onValue, iter.throw.bind(iter)); // repeat
    });
  };
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的value(某些异步函数的结果task{N})必须是一个承诺.你不能用回调来做到这一点.

还有待做的是将spawn技术应用到语言本身.因此,我们正在取代spawnasyncyieldawait,并即将ES7异步/ AWAIT:

var ourImportantFunction = async function() {
    //... some code 1
    var val1 = await task1();
    //... some code 2
    var val2 = await task2(val1);
    //... some code 3
    var val3 = await task3(val2);

    return val3;
}
Run Code Online (Sandbox Code Playgroud)

我建议你观看这个视频,以便更好地理解这个和其他一些即将到来的技术.如果这个人说得太快,请放慢播放速度(右下角的"设置",或者只需按[ shift+ <])

什么是最好的:只是回调,承诺或承诺与发电机 - 这是非常主观的问题.回调是目前最快的解决方案(本机承诺的表现现在非常糟糕).使用生成器的Promise为您提供了以同步方式编写异步代码的机会.但是现在它们比简单的回调要慢得多.


Iva*_*gin 10

Promises和Generators是不同的软件模式(构造):

  1. http://en.wikipedia.org/wiki/Futures_and_promises
  2. http://en.wikipedia.org/wiki/Generator_(computer_programming)

实际上,生成器不是异步的.

当您需要一次性获取一系列值时,生成器非常有用,但每个需求可以获得一个值.Generator会在每次调用时立即(同步)返回下一个值,直到它到达序列的末尾(或者在无限序列的情况下无穷无尽).

当您需要"推迟"可能尚未计算(或可能不可用)的值时,Promise非常有用.当值可用时 - 它是整个值(不是它的一部分),即使它是一个数组或其他复杂值.

您可以在维基百科文章中查看更多详细信息和示例.