es6+最佳入門實踐(10)

10.Generator

10.1.Generator是什麼?

Generator函數是ES6提供的一種異步編程解決方案。在它的內部封裝了多個狀態,因此,又可以理解爲一種狀態機,執行Generator函數後返回一個迭代器對象,使用這個迭代器對象可以遍歷出Generator函數內部的狀態

Generator函數和傳統函數的不同點有:1 函數定義的時候,function關鍵字後面加“*”, 2 內部使用yield關鍵字定義內部狀態


function* HelloGenerator() {
    yield "狀態1";
    yield "狀態2";
    yield "狀態3";
    yield "狀態4";
}

let hg = HelloGenerator();
console.log(hg.next());  //{value: "狀態1", done: false}
console.log(hg.next());  //{value: "狀態2", done: false}
console.log(hg.next());  //{value: "狀態3", done: false}
console.log(hg.next());  //{value: "狀態4", done: false}
console.log(hg.next());  //{value: undefined, done: true}

Generator函數被調用後,並不會立即執行完成,而是會在遇到yield關鍵字後暫停,返回的也不是函數的運行結果,而是一個執行內部狀態的指針對象(Iterator對象)

注意1: next方法內可以傳參數,這個參數的值作爲上一次狀態的返回值


function* HelloGenerator() {
    let result = yield "狀態1";
    console.log(result);
    yield "狀態2";
    yield "狀態3";
    yield "狀態4";
}

let hg = HelloGenerator();
console.log(hg.next());
console.log(hg.next('nodeing'));  

注意2: 可以使用for...of來遍歷Generator內部狀態


function* HelloGenerator() {

    yield "狀態1";
    yield "狀態2";
    yield "狀態3";
    yield "狀態4";
}

let hg = HelloGenerator();

for( let i of hg){
    console.log(i);
}

注意3: 對象沒有Symbol.Iterator屬性,我們可以手動添加,讓其具有Iterator接口

let obj = {};
function* gen() {
    yield 1;
    yield 2;
    yield 3;
    yield 4;
}
obj[Symbol.iterator] = gen;

for(let a of obj){
    console.log(a);
}

10.2.Generator應用

1.限制抽獎次數

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<button id="btn">抽獎</button>
<input type="text" id="ipt">
<script>
    let oBtn = document.getElementById('btn');
    let oIpt = document.getElementById('ipt');
    let start = gen(5);
    let timmer = null;
    oBtn.onclick = () => {
        start.next();
    };
    function draw(count) {
        clearInterval(timmer);
        let num = Math.floor(Math.random() * 30);
        let prize = 0;

        timmer = setInterval(()=>{
            prize++;
            if( num === prize){
                clearInterval(timmer);
                alert("還可以抽"+count+"次");
                return;
            }
            oIpt.value = prize;
        }, 100);

    }

    function* gen(count) {
        while (count > 0){
            count--;
            yield draw(count);
        }
    }
</script>
</body>
</html>

2.異步讀取文件

const fs = require('fs');

function readFile(path) {
    return new Promise((resolve, reject) => {
        fs.readFile(path, (err, data) => {
            if(err){
                reject(err)
            }else {
                resolve(data)
            }
        })
    })
}

function* asyncFile() {
    yield readFile('a.txt');
    yield readFile('b.txt');
    yield readFile('c.txt');
}

let gen = asyncFile();
gen.next().value.then((data)=>{
    console.log(data.toString());
    return gen.next().value;
}).then((data2)=>{
    console.log(data2.toString());
    return gen.next().value;
}).then((data3)=>{
    console.log(data3.toString())

});

如果覺得上面的寫法還比較麻煩的話,我們可以引入一個co模塊,讓aysncFile裏面的代碼自動執行

const co = require('co');

function* asyncFile() {
    let a = yield readFile('a.txt');
    let b = yield readFile('b.txt');
    let c = yield readFile('c.txt');
    console.log(a.toString(), b.toString(), c.toString())
}
co(asyncFile()).then(()=>{
    console.log('文件讀取完成')
});

視頻教程地址:http://edu.nodeing.com/course/50

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章