ES6 Generator 初體驗

ES6 Generator 初體驗

據說 ES6 的 Generator 是一個很神奇的函數,因此去了解了一下。 由於它不一樣於以往的尋常函數,可是帶來的體驗卻很是好 。這裏首先講了 Generator 是什麼,分割線後面用了一個例子來講明 Generator 到底好在哪裏 ~ (能夠選擇性閱讀~ )javascript

Generator 是一種異步編程解決方案,不明白?往下看 ~java

Generator 究竟是什麼?官方文檔是這樣說的:「Generators are functions which can be exited and later re-entered. Their context (variable bindings) will be saved across re-entrances.」ajax

意思就是 Generator 函數內部的執行是能夠暫停的。你可以執行到一半退出函數,同時執行到當前的上下文環境(包括變量等等)所有被保存下來,若是咱們稍後又進來繼續執行下一段,此時是在上次狀態的基礎上繼續往下執行。感受和別的函數很不同,如何去理解呢?編程

直接上代碼:json

var myGen = function*(){  // 定義一個 Generator 函數
  var one = yield 1; 
  var two = yield 2;
  var three = yield 3;
  console.log(one,two,three);
}
var gen = myGen();   
console.log(gen.next());  //第一次執行函數,輸出 {value:1,done:false}
console.log(gen.next());  //第二次執行函數,輸出 {value:2,done:false}
console.log(gen.next()); //第三次執行函數,輸出 {value:3,done:false}
console.log(gen.next());  //第四次執行函數,輸出{value:undefined,done:true}

能夠看到 function 後面加了一個 * 號,那是特有的 Generator 的寫法,function* 就表示我定義了一個 Generator function。內部還有三個 yield 。異步

那麼上面那段函數是如何執行的呢,一步一步來:異步編程

  1. 定義一個 Generator 函數 —— var myGen = function*(){…} ;函數

  2. var gen = myGen() 進行賦值,接下來想要執行函數須要調用 next(),由於 Generator 函數不會本身執行,next() 能夠 return 一個對象,包含兩個屬性,一個是輸出的值(yielded value),還有一個是 done property,表示這個 Generator 函數是否已經輸出了最後一個值(yielded its last value)了;url

  3. 調用 next() 後,執行函數內部第一條語句 var one = yield 1,因爲這條函數執行順序是自右向左,因此先執行 yield 1,yield 1 這裏的做用相似 return 1,返回一個 1 ,同時暫停了函數的執行,它後面的語句並不會繼續執行下去。因此第一句 console.log(gen.next()) 輸出 1。code

  4. 以此類推,最後的 console.log(gen.next()) 結果爲 {value:undefined,done:true},由於函數已經沒有任何 yield,沒有 return 任何值回來,done 爲 true 表示這個 Generator 函數執行結束了。

  5. myGen 函數內的 console.log(one,two,three) 會輸出什麼呢? 1,2,3 ?猜錯了!其實這裏輸出的是 undefined,undefined,undefined。由於 yield 在 var one = 和 1 中間,因此 1 並無賦值到變量 one 上面。

    下面加一點好玩的東西:把上面全部的 console.log() 改爲下面這個樣子。

    console.log(gen.next());
    console.log(gen.next(4));
    console.log(gen.next(5));
    console.log(gen.next('a'));

    這時, console.log(one,two,three) 輸出的就是 4,5,a。

    WHY?? 剛剛說到 var one = yield 1;的執行順序是自右向左的,執行到 yield 1就暫停了,因此並無給 one 賦值,因此執行 console.log(gen.next(4)) 語句的時候,把參數 4 賦值給了 one ,而後繼續執行 yield 2,以此類推...

然而這看起來好像並無什麼卵用?別急,繼續往下看 ~

———————————我是分割線—————————————

首先咱們知道日常常常會遇到這樣一種狀況,就是須要寫嵌套的 AJAX,特別是比較複雜的項目裏面,AJAX 一層層嵌套( 會存在多層回調嵌套,叫作 Pyramid of Doom),體驗很是糟糕。

好比下面這樣子的:

$.ajax({          // 第一個AJAX
  type:'GET',
  url:'booklist.json',
  success:function(booklist){
        console.log(booklist);
        $.ajax({   // 第二個AJAX
          type:'GET',
          url:'book.json?id='+booklist.id,
          success:function(book){
                console.log(book);
                $.ajax({    //第三個AJAX
                  type:'GET',
                  url:'comments.json?id='+book[0].id,
                  success:function(comments){
                        console.log(comments);
                    },
                  error:function(xhr,status,error){
                        //處理一些東西
                    }
                });
            },
          error:function(xhr,status,error){
                //處理一些東西
            }
        });
    },
  error:function(xhr,status,error){
        //處理一些東西
    }
})

三個AJAX嵌套在一塊兒,雖然被簡化了(一些數據處理直接用 console.log() 替代),可是仍是看起來比較亂,一亂起來中午吃個飯回來都找不到上次寫到哪裏了,然而實際業務中要作的處理也絕對比這多不少。

這裏先用一種比較普通的方式來處理上面那大段代碼:

$.ajax({
  type:'GET',
  url:'booklist.json',
  success:getbook,
  error:handleError
});
function getbook(booklist){
  console.log(booklist);
  $.ajax({
    type:'GET',
    url:'book.json?id='+booklist.id,
    success:getComments,
    error:handleError
    });
}
function getComments(book){
  console.log(book);
  $.ajax({
    type:'GET',
    url:'comments.json?id='+book[0].id,
    success:function(comments){
        console.log(comments);
        },
    error:handleError
    });
}
function handleError(xhr,status,error){
  //處理一些東西
}

上面的代碼封裝了三個 function,看起來整齊一些了,而且全部的 error 處理都經過調用本身封裝好的 handleError 去作,然而咱們的代碼量並無減小多少。

下面用 Promise 對代碼進行處理:

$.get(booklist.json).then(function(booklist){
  console.log(booklist);
  return $.get('book.json?id='+booklist.id);
}).then(function(book){
  console.log(book);
  return $.get('comments.json?id='+book[0].id)
}).then(function(comments){
  console.log(comments);
},handleError);
​
function handleError(xhr,status,error){
    //處理一些東西
}

Promise 經過 .then() 將函數串聯在一塊兒,它採用了同步的方式去處理異步的問題,去除了一層層的回調嵌套,error 處理只須要最後調用一次 handleError 就夠了,彷佛已經很好了,不過這裏還有更好的方法——Generator。

下面是用 Generator 處理:

Promise.coroutine(function*(){
  var booklist = yield $.get('booklist.json');
  console.log(booklist);
  var book = yield $.get('book.json?id='+booklist.id);
    console.log(book);
  var comments = yield $.get('comments.json?id='+book[0].id);
    console.log(book);
})().catch(function(errs){
  //處理一些東西
})

對比第一段代碼,瞬間神清氣爽了!Promise.coroutine 是專門用來給 Generator 用的,做用就至關於最開始的那個帶上參數的 next()。咱們不須要去把回調函數嵌套在一塊兒,或者串聯在一塊兒就可以獲得想要的結果,是否是很是贊~?!!ꉂ ೭(˵¯̴͒ꇴ¯̴͒˵)౨」

References:

https://www.youtube.com/watch?v=QO07THdLWQo

https://www.youtube.com/watch?v=obaSQBBWZLk

相關文章
相關標籤/搜索