Generator(生成器) 學習理解與實踐

created at 2019-04-08

總結

  • 異步編程解決方案
  • 可理解爲一種狀態機,封裝了多個內部狀態
  • 可返回一個指向內部狀態的指針對象(遍歷器對象Interator),因此可理解爲其是一個遍歷器對象生成函數
  • yield(產出),定義不一樣的內部狀態,yield後跟表達式。
  • yield 表達式只能放在Generator函數中
  • (yield 表達式) 整個沒有返回值,next()的參數能夠被認爲是上一個yield的返回值。
  • V8引擎直接忽略第一次next()的參數,由於沒有上一次yield
  • 調用next方法,是指針從函數頭部或上一次中止的地方開始執行,直到遇到下一個yield表達式或return
  • 當next的返回值的value屬性爲yield後表達式的結果或return後的值,done屬性爲true時表示遍歷yield結束
  • 對象中使用const obj = { myGeneratorMethod(){} } 等同於 obj = { myGeneratorMethod:function (){} }
  • yield* 用於在一個generator函數中執行另外一個generator函數,而且會將另外一個的yield所有執行完畢纔會繼續執行當前generator中的yield

基礎語法

function* generatorTest() {
    console.log('第一個yield以前的語句');
    yield 'yield 1'
    yield 'yield 3: 在表達式中要加括號' + (yield 'yield 2: in expression')
    console.log('yield 以後 return以前');
    return 'return'
}

const gt = generatorTest()
console.log(gt);
// 遍歷器對象

/*
* 第一次調用是從函數頭部開始執行,若是沒有yield,也須要執行一次next纔會執行這些語句
*/
console.log(gt.next());
// 第一個yield以前的語句
// {value: "yield 1", done: false}

console.log(gt.next());
// {value: "yield 2: in expression", done: false}

console.log(gt.next());
// {value: "yield 3: 在表達式中要加括號undefined", done: false}
// 上面出現undefined的緣由是next沒有加參數

console.log(gt.next());
// yield 以後 return以前
// {value: "return", done: true}

console.log(gt.next());
// {value: "undefined", done: true}

實現斐波拉契數列

連接html

給原生對象添加Iterator

先展現for of 對generator的做用git

function* generatorForOf(){
    yield 1;
    yield 2;
    return 3;
}
/*
* for of 能夠遍歷Generator生成的Iterator對象
* 這裏不能再遍歷 gt 由於它已執行完畢
* 不會遍歷return的值
*/
for (let item of generatorForOf()) {
    console.log('for of :', item);
}

給原生對象添加iterator, 讓其能夠被for of 遍歷es6

function* objectAddIterator(obj) {
    const props = Reflect.ownKeys(obj)

    for (const key of props) {
        yield [key, obj[key]]
    }
}

const nativeObj = {
    a: 12,
    b: 34,
    [Symbol('symbol c')]: 3
}

for (const [key, value] of objectAddIterator(nativeObj)) {
    console.log(typeof key === 'symbol' ? key.description : key, value);
}

應用場景

異步ajax請求

代碼中的loading函數代碼行數較多,也並不是關鍵代碼,因此不做展現。查看loading代碼github

<div id="ajax">初始數據</div>
<button onclick="getSomeList()">請求ajax數據</button>
function requestData(callback) {
    function ajaxFn() {
        setTimeout(() => {
            ar.next('ajax返回結果')
        }, 2000);
    }

    function* asyncReqData() {
        loading(true)
        const result = yield ajaxFn()
        callback(result)
        loading(false)
    }

    const ar = asyncReqData()
    ar.next()
}

function getSomeList() {
    requestData((res) => {
        document.getElementById('ajax').innerHTML = res
    })
}

控制同步操做的流程

function controlFlow() {
    const child1 = [() => {console.log('--',1); return 'return 1'}, () => {console.log('--',2); return 'return 2'}]
    const child2 = [() => {console.log('--',3); return 'return 3'}, () => {console.log('--',4); return 'return 4'}]
    function* generatorControl(child) {
        console.log('===========');
        for (let i = 0; i < child.length; i++) {
            yield child[i]()
        }
    }
    let parent = [{c: child1}, {c: child2}];

    function* parentFn(p){
        for (let i=0; i< p.length; i++){
            yield* generatorControl(p[i].c);
        }
    }

    for (let step of parentFn(parent)) {
        console.log(step);
    }
}

controlFlow()

本文包括對generate基礎的學習與練習,與一些心得!【會持續學習,更新】ajax

詳細學習請移步下方參考連接express

參考:編程

歡迎交流 Github
相關文章
相關標籤/搜索