Promises和generator允许您编写异步代码。我不明白为什么这两种机制都是在ECMA脚本6中引入的。什么时候最好使用promises,什么时候使用生成器?
答案 0 :(得分:90)
这两种技术之间没有对立面。它们共存在一起很好地相互补充。 Promise使您能够获得尚未提供的异步操作的结果。它解决了Pyramid of Doom问题。所以而不是:
function ourImportantFunction(callback) {
//... some code 1
task1(function(val1) {
//... some code 2
task2(val1, function(val2) {
//... some code 3
task3(val2, callback);
});
});
}
你可以写:
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);
但即使有了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);
最简单的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
});
};
}
正如您所看到的,value
(某些异步函数task{N}
的结果)必须是一个承诺。你不能用回调来做到这一点。
还有待做的是将spawn
技术应用于语言本身。因此,我们将spawn
替换为async
,将yield
替换为await
,然后转到ES7 async/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;
}
我建议您观看this video以更多地了解这一点以及其他一些即将推出的技巧。如果这个人说得太快,请放慢播放速度(右下角的“设置”,或者只需按[shift
+ <
])
什么是最好的:只是回调,承诺或承诺与发电机 - 这是非常主观的问题。回调是目前最快的解决方案(本机承诺的表现现在非常糟糕)。使用生成器的Promise为您提供了以同步方式编写异步代码的机会。但是现在它们比简单的回调要慢得多。
答案 1 :(得分:10)
Promises和Generators是不同的软件模式(构造):
事实上,生成器不是异步的。
当您需要一次性获取一系列值时,生成器非常有用,但每个需求可以获得一个值。 Generator会在每次调用时立即(同步)返回下一个值,直到它到达序列的末尾(或者在无限序列的情况下无穷无尽)。
当您需要推迟时,承诺非常有用。可能尚未计算(或可能不可用)的值。当值可用时 - 它是整个值(不是它的一部分),即使它是数组或其他复杂值。
您可以在维基百科文章中查看更多详细信息和示例。