生成器从本质上来讲,是一种特殊的迭代器。为何这么说呢,下面来看一段代码:segmentfault
Example异步
function* gen(arg){ yield 2; yield arg; } let genHandle = gen(3); for(let i of genHandle){ console.log(i); // 依次打印:2,3 } let genHandle2 = gen(4); console.log(genHandle2.next()); // { value: 2, done: false } console.log(genHandle2.next()); // { value: 4, done: false } console.log(genHandle2.next()); // { value: undefined, done: true }
代码解读:从上面代码能够看出生成器实际上是一个变异的函数,和通常的函数没什么不一样,只是多了一个 * 来区分这是一个生成器。固然生成器内部多了一个yeild语句,做用显而易见是为了中止继续执行下面的代码,至关于return的做用同样,可是不一样的是它能够保存进度,能够经过代码控制继续执行。并且这里的yeild必定要在生成器的做用域范围内才会有效,这点要注意。在执行完生成器返回的对象genHandle和genHandle2能够看出,它们都是迭代器,也就是说生成器执行结果返回的是迭代器对象,即生成器能够当作是一个迭代器的构造器,能够用来构建生成迭代器。yield在生成器构建迭代器的过成中的做用中就相似于切割代码的做用,把代码切割成一个能够迭代的集合。下面是上面的gen生成器转成ES5的代码,以下:async
Example函数
function gen(arg) { return regeneratorRuntime.wrap(function gen$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: _context.next = 2; return 2; case 2: _context.next = 4; return arg; case 4: case "end": return _context.stop(); } } }, _marked[0], this); }
Example:为了便于理解,下面是我实现的一个简单的regeneratorRuntime.wrap函数来生成迭代器:this
var context = { next:0, prev:null, gen$:null, done:false, stop:function(){ this.done = true; } }; Object.defineProperty(context, Symbol.iterator, { enumerable: false, writable: false, configurable: true, value: function () { var me = this; return { next: function () { var nextValue = me.gen$(me); return { value: nextValue, done: me.done } } } } }); var regeneratorRuntime = { wrap:function(_gen){ context.gen$ = _gen; return context; } } function gen(arg) { return regeneratorRuntime.wrap(function gen$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: _context.next = 2; return 2; case 2: _context.next = 4; return arg; case 4: case "end": return _context.stop(); } } }); } var b = gen(3); for(var c of b){ console.log(c); // 结果为:2,3 }
Examplecode
// 正常异步执行 function demo(){ new Promise(function(resolve,reject){ resolve(3) }).then((value)=>{ console.log(value) }) console.log(4) } demo(); // 执行结果依次是:4,3 // 生成器异步转同步 let gen = null; function* genDemo(){ yield setTimeout(()=>{ console.log(3); gen.next(); },100) console.log(4) } gen = genDemo(); gen.next() // // 执行结果依次是:3,4 // async...await...异步转同步 async function asyncDemo(){ await new Promise(function(resolve,reject){ resolve(3) }).then((value)=>{ console.log(value) }) console.log(4) } asyncDemo(); // 执行结果依次是:3,4
代码解读:从上述的例子能够看出,生成器是能够解决异步若是转成同步代码的问题,而async...await...的实现原理其实也是基于生成器来实现的,不过这里要注意的是async...await...必需要配合Promise来实现,由于Promise的决议回调函数里面集成了相似于生成器gen.next()这样的代码来控制继续执行代码。对象