承诺和生成器允许您编写异步代码。我不明白为什么在ECMA脚本6中同时引入了这两种机制。什么时候最好使用Promise?什么时候使用生成器?
这两种技术之间没有对立。它们共存并很好地互补。承诺使您能够获得尚不可用的异步操作的结果。它解决了厄运金字塔问题。所以代替:
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);
但是即使有承诺,您也必须以异步方式编写代码- 您必须始终将回调传递给函数。编写异步代码比同步代码难得多。即使有承诺,当代码很大时,也很难看清算法(嗯,这是非常主观的,有人可以与它争论。但是对于大多数程序员来说,我认为这是事实)。因此,我们想以同步方式编写异步代码。那就是发电机来帮助我们的地方。因此,您可以编写上面的代码,而不是上面的代码:
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实现可能是这样的:
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})必须是一个承诺。您不能通过回调来做到这一点。
value
task{N}
剩下要做的就是将spawn技术实现为语言本身。因此,我们正在取代spawn以async并yield用await,并即将ES7异步/ AWAIT:
async
yield
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; }
我建议您观看此视频,以更全面地了解此技术和其他一些即将来临的技术。如果此人对您说得太快,请放慢播放速度(位于右下角的“设置”,或直接按[ shift+ <])
shift
<
最好的是什么:仅仅是回调,promise或生成器的promise- 这是一个非常主观的问题。回调是目前可能的最快解决方案(现在,本机承诺的履行非常糟糕)。生成器的承诺使您有机会以同步方式编写异步代码。但是现在,它们比简单的回调要慢得多。