![](/img/trans.png)
[英]Ecma6 promise: how to use Ecma6 promise to rewrite jquery $.when?
[英]ECMA6 generators: yield promise
据我了解,ECMA6 生成器应该能够屈服于返回 promise 的 function,最终返回已解决/拒绝。 让代码读起来更像同步代码,避免回调地狱。
我正在使用 node.js v0.12.2 和 --harmony 和以下代码。
var someAsyncThing = function() {
return new Promise(function(resolve, reject) {
resolve("I'm Resolved!");
});
};
someAsyncThing().then(function(res) {console.log(res);});
// Works as expected: logs I'm Resolved!
function* getPromise() {
var x = yield someAsyncThing();
console.log("x: " + x); // Fails x undefined
}
var y = getPromise();
console.log(y); // returns {}
console.log(y.next());
// Fails: logs { value: {}, done: false }
我的代码基于我能够在网上找到的几个示例。 我究竟做错了什么?
据我了解,ECMA6生成器应该能够屈服于一个返回promise的函数,最终返回已解决/拒绝的函数。
不,那不是他们的目的。 ES6生成器应该提供一种编写迭代器的简单方法 - 每次调用生成器函数都会产生一个迭代器。 迭代器只是一个值序列 - 就像一个数组,但是动态消耗并且懒惰地生成。
现在,生成器可以被滥用于异步控制流,通过生成一系列异步消耗的promise并使迭代器与每个等待的promise的结果一起推进。 请看这里没有承诺的解释。
所以你的代码缺少的是实际等待承诺并推进你的生成器的消费者。 通常你会使用一个专用的库(比如co或task.js ),或许多承诺库提供的辅助函数之一( Q , Bluebird , when ,......),但为了这个答案,我将展示一个简化的一个:
function run(gf) {
let g = gf();
return Promise.resolve(function step(v) {
var res = g.next(v);
if (res.done) return res.value;
return res.value.then(step);
}());
}
现在使用此功能,您可以实际“执行”您的getPromise
生成器:
run(getPromise).then(console.log, console.error);
tl; dr:发电机产生的承诺必须向前移动发电机。
如果您查看http://davidwalsh.name/async-generators中的第一个示例,您会注意到async函数实际上向前移动了迭代器:
function request(url) {
// this is where we're hiding the asynchronicity,
// away from the main code of our generator
// `it.next(..)` is the generator's iterator-resume
// call
makeAjaxCall( url, function(response){
it.next( response ); // <--- this is where the magic happens
} );
// Note: nothing returned here!
}
但是既然你正在处理承诺,我们可以稍微改进一下。 y.next().value
返回一个promise,你必须听这个promise。 所以不要编写console.log(y.next())
,而是写下:
var promise = y.next().value;
promise.then(y.next.bind(y)); // or promise.then(function(v) { y.next(v); });
当然这不太实用,因为现在你无法访问下一个产生的值而且你不知道何时完成发生器。 但是,您可以编写一个递归函数来处理它。 这就是runGenerator
在本文runGenerator
介绍的内容。
我想出了以下示例来执行产生承诺的 function 生成器:
_asyncToGenerator()
helper function that was derived from https://babeljs.io transpiler for converting async/await syntax to function generator yield syntax function sleep(delay) { return new Promise(function (resolve, reject) { setTimeout(resolve, delay); } ); } _asyncToGenerator(function *() { console.log('one'); yield sleep(1000); console.log('two'); yield sleep(1000); console.log('three'); })(); function _asyncToGenerator(fn) { return function() { var self = this, args = arguments return new Promise(function(resolve, reject) { var gen = fn.apply(self, args) function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value) } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err) } _next(undefined) }) } } function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg) var value = info.value } catch (error) { reject(error) return } if (info.done) { resolve(value) } else { Promise.resolve(value).then(_next, _throw) } }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.