從ES6生成器(Generator)原理解讀,到理解ES7的asyn...await...

從ES6生成器(Generator)原理解讀,到理解ES7的asyn...await...

ES6生成器原理解讀

生成器從本質上來講,是一種特殊的迭代器。爲何這麼說呢,下面來看一段代碼: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
}

理解ES7的 asyn...await...

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()這樣的代碼來控制繼續執行代碼對象

相關文章
相關標籤/搜索