生成器從本質上來講,是一種特殊的迭代器。爲何這麼說呢,下面來看一段代碼: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()這樣的代碼來控制繼續執行代碼。對象