下面小編就為大家?guī)硪黄贜ode.js中使用Javascript Generators詳解。小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考
Generators是Javascript的一種協(xié)同程序( coroutine 簡稱:協(xié)程)風格,是指那些可以在執(zhí)行時暫停然后又恢復的函數(shù),該函數(shù)是在functi配以星號符號形式如function* ,函數(shù)內(nèi)有些特征關(guān)鍵詞如yield 和yield*。
function* generatorFn () {
console.log('look ma I was suspended')
}
var generator = generatorFn() // [1]
setTimeout(function () {
generator.next() // [2]
}, 2000)
對代碼中標注的[1]和[2]解釋如下:
1. 這是一個generator以暫停方式開始. 這時沒有控制臺輸出。
2.通過調(diào)用其next()方法,這個generator才會執(zhí)行,運行直至它碰到下一個yield關(guān)鍵詞或return,現(xiàn)在我們就有了控制臺輸出。
再看一個案例:
function *generator() {
console.log('Start!');
var i = 0;
while (true) {
if (i < 3)
yield i++;
}
}
var gen = generator();
以上這段代碼類似第一個,只是在generator函數(shù)中多了yield關(guān)鍵詞,以上這段代碼被調(diào)用時,不會立即執(zhí)行,而是暫停待命的狀態(tài),因此不會有Start輸出。直到其next()調(diào)用才執(zhí)行。
var ret = gen.next();
// Start!
console.log(ret);
// {value: 0, done: false}
上面ret是generator結(jié)果. 它有兩個屬性:
■value, 在generator函數(shù)中的yield值,
■done, 這是一個標識表示generator函數(shù)是否返回.
繼續(xù)代碼如下:
console.log(gen.next());
// {value: 1, done: false}
console.log(gen.next());
// {value: 2, done: false}
console.log(gen.next());
// {value: undefined, done: true}
generator在同步編程中沒有什么玄機,特別適合在異步編程中。
generator有兩個特點:
1.能選擇跳出一個函數(shù),讓外部代碼決定什么時候再跳回這個函數(shù)繼續(xù)執(zhí)行。
2.能夠進行異步控制。
看下面異步執(zhí)行代碼:
var gen = generator();
console.log(gen.next().value);
setTimeout(function() {
console.log(gen.next().value);
console.log('第一步');
}, 1000);
console.log('第二步');
輸出是:
0
第二步
1
第一步
也就是說,不會在setTimeout這里等待計時結(jié)束,而是直接繼續(xù)“第二步”,不會在setTimeout堵塞。
再看另外一段代碼:
function* channel () {
var name = yield 'hello, what is your name?' // [1]
return 'well hi there ' + name
}
var gen = channel()
console.log(gen.next().value) // hello, what is your name? [2]
console.log(gen.next('billy')) // well hi there billy [3]
在遍歷時也可以使用*:
function* iter () {
for (var i = 0; i < 10; i++) yield i
}
for (var val of iter()) {
console.log(val) // outputs 1?—?9
}
普遍的誤解
既然我可以暫停一個函數(shù)執(zhí)行,那么是不是讓它們并行執(zhí)行呢?不是,因為Javascript是一個單線程,如果你想尋求提升性能,generator并不是你的菜。
比如下面代碼分別執(zhí)行斐波那契數(shù):
function fib (n) {
var current = 0, next = 1, swap
for (var i = 0; i < n; i++) {
swap = current, current = next
next = swap + next
}
return current
}
function* fibGen (n) {
var current = 0, next = 1, swap
for (var i = 0; i < n; i++) {
swap = current, current = next
next = swap + next
yield current
}
}
性能結(jié)果如下:(越高越好)
results:
regular 1263899
generator 37541
generators閃亮點
Generators 能簡化JavaScript中函數(shù)的復雜性。
懶賦值
懶賦值雖然可以使用JS的閉包實現(xiàn),但是使用yield會有很大的簡化,通過暫停和恢復,我們能夠在我們需要的時候獲取數(shù)值,比如上面fibGen函數(shù)可以在我們需要時拉取新值:
var fibIter = fibGen(20)
var next = fibIter.next()
console.log(next.value)
setTimeout(function () {
var next = fibIter.next()
console.log(next.value)
},2000)
當然還使用for循環(huán):依然是懶賦值
for (var n of fibGen(20) {
console.log(n)
}
無限序列
因為可以懶賦值,那么可能表演一些Haskell招數(shù), 類似infinite sequences. 這里能夠yield一個無限序列的數(shù)量。
function* fibGen () {
var current = 0, next = 1, swap
while (true) {
swap = current, current = next
next = swap + next
yield current
}
}
我們看看一個斐波那契數(shù)流的懶賦值,要求它返回5000以后的第一個斐波那契數(shù):
for (var num of fibGen()) {
if (num > 5000) break
}
console.log(num) // 6765
異步流程控制
使用generators實現(xiàn)異步流程控制,最常見是各種 promise庫包,那么它是如何工作呢?
在Node領(lǐng)域,每個事情都是和回調(diào)有關(guān),這是我們的低層次異步功能,我們可以使用generators 建立一個通訊通道,從而使用同步編程的風格編寫異步代碼。
run(function* () {
console.log("Starting")
var file = yield readFile("./async.js") // [1]
console.log(file.toString())
})
注釋1表示程序會在等待async.js返回結(jié)果以后再繼續(xù)。
genify是一個將generators帶入平常編程環(huán)境的框架,使用如下:
npm install genify 進行安裝,代碼如下:
var Q = require('q');
var fs = require('fs');
var genify = require('genify');
// wrap your object into genify function
var object = genify({
concatFiles: function * (file1, file2, outFile) {
file1 = yield Q.nfcall(fs.readFile, file1);
file2 = yield Q.nfcall(fs.readFile, file2);
var concated = file1 + file2;
yield Q.nfcall(fs.writeFile, outFile, concated);
return concated;
}
});
// concatFiles是一個generator函數(shù),它使用generator強大能力。
object.concatFiles('./somefile1.txt', './somefile2.txt', './concated.txt').then(function (res) {
// do something with result
}, function (err) {
// do something with error
});
以上這篇在Node.js中使用Javascript Generators詳解就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考