generator的基本使用及co庫的原理

一般ajax請求都會用到異步調用問題,爲了保證調用順序的正確性,通常會用到callback,後來出現了promise的解決方案。
在異步編程中,還有一種解決方案,那就是generator生成器函數,這個函數會返回一個迭代器。ajax

特色:函數聲明只是多了個*號來表示這是一個生成器函數,而且通常能夠在函數內看到yield關鍵字。
原理:它會將一個函數分爲若干個小函數,而且返回一個迭代器,經過調用迭代的next方法(移動指針),內部遍歷值、狀態,保持正確的執行順序。每次調用next方法,都會向下執行一步。
用法:
1.先產出,下一個next負責傳值,而後接收新值。
2.yield後面跟着的是value值(產出值)。 yield等號前面的 是咱們當前調用next傳進來的 值。沒有等號表明不接收新值。 注意點:迭代器的第一個next執行,傳值是無效的。
function *read(){
    console.log(1);
    var content1 = yield 'qs';
    console.log(content1);
    var content2 = yield '9';![圖片描述][1]
    console.log(content2);
    return content2;
}
var it = read();
var a = it.next() //輸出 1  a:{value:'qs',done:false}
var b = it.next('hello')//輸出hello  b:{value:'9',done:false}
var c = it.next('generator')//輸出generator  c:{value:'generator',done:true}
var d = it.next('123')//輸出generator  c:{value:undefined,done:true}
console.log(a,b,c,d)

具體的執行步驟,見圖分解圖片描述npm

產出的值 是一個object,包含兩個key :value 和 done value
表示產出的值,done表示執行狀態(迭代器是否執行完成,所有遍歷一遍) 當done
爲true時表示遍歷完成。以後再次執行next,就沒有產出了,因此value爲undefined,done仍舊是true;

用處:generator通常和promise結合一塊兒用編程

let fs = require('fs');
let blueBird =  require('bluebird');
let read2 = blueBird.promisify(fs.readFile);
function *r(){
    let content1 = yield read2('./1.txt','utf8');
    let content2 = yield read2(content1,'utf8');
    return content2
}
let it2 = r();
it2.next().value.then(res=>{
   it2.next(res).value.then(res=>{
        console.log(res);
        console.log(it2.next(res));//須要給content2賦值,而後產出{ value: '大大大', done: true }
    })
});

爲了更好的結合promise使用,出現了co庫。
co庫的做用就是:把一個生成器函數的迭代器,最後一步執行完畢後,而後統一執行一個成功回調
安裝:npm install co --savepromise

let co = require('co');
function *r2(){
    let content1 = yield read2('./1.txt','utf8');
    let content2 = yield read2(content1,'utf8');
    return content2
}
co(r2).then(function(res){console.log(res,11111111111111)});

co庫實現原理,就是利用產出值的done的狀態,去判斷是否須要再次遞歸執行next方法。異步

function co(it){
    return new Promise(function(resolve,reject){
        function next(data){
            let {value,done}= it.next(data);
            if(!done){
                value.then(res=>{
                    next(res);
                },reject)
            }else{
                resolve(value)
            }
        }
        next();
    })
}
相關文章
相關標籤/搜索