ES6-Generator

Generator

關鍵詞:狀態機,遍歷器,同步方式寫異步方法git

基本概念

  • 形式上,Generator函數是一個普通函數,可是有兩個特徵。
    • function關鍵字與函數名之間有一個星號。
    • 二是,函數體內部使用yield語句,定義不一樣的內部狀態。
function* helloWorldGenerator() {
    yield 'hello';
    yield 'world';
    return 'ending';
}
var hw = helloWorldGenerator();
var h = helloWorldGenerator();
  • 調用Generator函數,返回一個遍歷器對象,表明Generator函數的內部指針。
// 接上面的demo

hw.next()
// { value: 'hello', done: false }

hw.next()
// { value: 'world', done: false }

hw.next()
// { value: 'ending', done: true }

hw.next()
// { value: undefined, done: true }

yield語句

  • yield語句不能用在普通函數中,不然會報錯
(function (){
    yield 1;
})()
  • yield語句若是用在一個表達式之中,必須放在圓括號裏面
console.log('Hello' + yield); // SyntaxError
console.log('Hello' + yield 123); // SyntaxError

console.log('Hello' + (yield)); // OK
console.log('Hello' + (yield 123)); // OK
  • yield語句用做函數參數或賦值表達式的右邊,能夠不加括號
foo(yield 'a', yield 'b'); // OK
let input = yield; // OK

return()

  • 若是主動調用return()方法,Generator函數將被終結
function* gen(){
    yield 1;
    yield 2;
    yield 3;
}
var g = gen();
g.next() // {value: 1, done: false}
g.return('foo') // {value: 'foo', done: true}
g.next() // {value: undefined, done: true}
  • 可是,若是Generator函數內部有try...finally代碼塊,那麼return方法會推遲到finally代碼塊執行完再執行。
function* gen(){
    try{
        yield 1;
    }finally{
        yield 2;
    }
    yield 3;
}
var g = gen();
g.next() // {value: 1, done: false}
g.return(10) // {value: 2, done: false}
g.next() // {value: 10, done: true}

yield*

  • 在一個Generater函數內部直接調用另一個Generater函數無效
function* outer(){
    yield 1;
    yield inner();
    return 3;
}
function* inner(){
    yield 2;
}
var o = outer();
o.next(); // {value: 1, done: false}
o.next(); // {value: inner, done: false}
o.next(); // {value: 3, done: true}
  • 上面的狀況能夠使用yield*解決
function* outer(){
    yield 1;
    yield* inner(); // 調用方法與上面不一樣
    return 3;
}
function* inner(){
    yield 2;
}
var o = outer();
o.next(); // {value: 1, done: false}
o.next(); // {value: 2, done: false} // 返回結果與上面不一樣
o.next(); // {value: 3, done: true}
  • 任何數據結構只要有Iterator接口,就能夠被yield*遍歷。
function* demo(){
    yield* [1, 2, 3];
}
var d = demo();
d.next(); // {value: 1, done: false}
d.next(); // {value: 2, done: false}
d.next(); // {value: 3, done: false}
d.next(); // {value: undefined, done: true}
  • 若是被代理的Generator函數有return語句,那麼就能夠向代理它的Generator函數返回數據。
function* outer(){
    yield 1;
    var i = yield* inner();
    yield 2 + i;
}
function* inner(){
    return 2;
}
var o = outer();
o.next(); // {value: 1, done: false}
o.next(); // {value: 4, done: false}

做爲對象屬性的Generator函數

  • 若是一個對象的屬性是Generator函數,能夠簡寫成下面的形式。
let obj = {
    * gen(){
        yield 1;
    }
};
var g = obj.gen();
g.next(); // {value: 1, done: false}

Generator函數的this

應用

  • 異步操做的同步化表達,邏輯更清晰
function* render(){
    showLoading();
    var res = yield getData();
    hideLoading();
    console.log(res); // 打印ajax的結果
}
function getData(){
    $.ajax().done(function(res){
        r.next(res);
    });
}
var r = render();
r.next();
  • 控制流管理,擺脫回調函數多層嵌套
// callback方式
function step(){
    step1(function(res1){
        step2(res1, function(res2){
            step3(res2, function(res3){
                console.log(res3);
            })
        })
    })        
}
// promise方式
function step(){
    step1()
    .then(step2)
    .then(step3)
    .then(function({
        // do something
    }))        
}
// Generator方式
function step(){
    var res1 = yield step1();
    var res2 = yield step2(res1);
    var res3 = yield step3(res2);
}
  • 多任務並行。若是yield語句後面的參數,是一個具備遍歷器接口的對象,yield會遍歷這個對象,再往下執行。這意味着,多個任務按順序一個接一個執行時,yield語句能夠按順序排列。多個任務須要並列執行時(好比只有A任務和B任務都執行完,才能執行C任務),能夠採用數組的寫法。
function execTaskA(){
    return new Promise(function(resolve, reject){
        if(true){
            resolve('a')
        }
    })
}
function execTaskB(){
    return new Promise(function(resolve, reject){
        if(true){
            resolve('b')
        }
    })
}
function* execTasks(){
    var [resA, resB] = yield [execTaskA(), execTaskB()];
    // let resB = yield* execTaskB();
    console.log(resA, resB);
}
var t = execTasks();
t.next();
  • 關於Generator函數的自動執行,能夠關注github上的co組件
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息