首頁 >web前端 >js教程 >在Node.js中使用Javascript Generators詳解_javascript技巧

在Node.js中使用Javascript Generators詳解_javascript技巧

WBOY
WBOY原創
2016-05-16 15:01:541878瀏覽

Generators是Javascript的一種協同程式( coroutine 簡稱:協程)風格,是指那些可以在執行時暫停然後又恢復的函數,該函數是在functi配以星號符號形式如function* ,函數內有些特徵關鍵字如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.透過呼叫其next()方法,這個generator才會執行,運行直至它碰到下一個yield關鍵字或return,現在我們就有了控制台輸出。

再看一個案例:

function *generator() {

 console.log('Start!');

 var i = 0;

 while (true) {

  if (i < 3)

   yield i++;

 }

}
var gen = generator();

以上這段程式碼類似第一個,只是在generator函數中多了yield關鍵字,以上這段程式碼被呼叫時,不會立即執行,而是暫停待命的狀態,因此不會有Start輸出。直到其next()呼叫才執行。

var ret = gen.next();

// Start!

console.log(ret);

// {value: 0, done: false}

上面ret是generator結果. 它有兩個屬性:

■value, 在generator函數的yield值,

■done, 這是一個標識表示generator函數是否回傳.

繼續程式碼如下:

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.能選擇跳出一個函數,讓外部程式碼決定什麼時候再跳回這個函數繼續執行。
2.能夠進行非同步控制。

看下面非同步執行程式碼:

var gen = generator();

console.log(gen.next().value);

setTimeout(function() {

 console.log(gen.next().value);

 console.log('第一步');

}, 1000);

console.log('第二步');

輸出是:

0
第二步
1
第一步

也就是說,不會在setTimeout這裡等待計時結束,而是直接繼續“第二步”,不會在setTimeout堵塞。

再看另外一段程式碼:

function* channel () {

 var name = yield 'hello, what is your name&#63;' // [1]

 return 'well hi there ' + name

}

var gen = channel()

console.log(gen.next().value) // hello, what is your name&#63; [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&#63;—&#63;9

}

普遍的誤解

既然我可以暫停一個函數執行,那麼是不是讓它們並行執行呢?不是,因為Javascript是一個單線程,如果你想尋求提升效能,generator並不是你的菜。

例如下面程式碼分別執行斐波那契數:

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

 }

}

效能結果如下:(越高越好)

results:
regular 1263899
generator 37541

generators閃亮點

Generators 能簡化JavaScript中函數的複雜度。

懶賦值

懶賦值雖然可以使用JS的閉包實現,但是使用yield會有很大的簡化,透過暫停和恢復,我們能夠在我們需要的時候獲取數值,比如上面fibGen函數可以在我們需要時拉取新值:

var fibIter = fibGen(20)

var next = fibIter.next()

console.log(next.value)

setTimeout(function () {

 var next = fibIter.next()

 console.log(next.value)

},2000)

当然还使用for循环:依然是懒赋值

for (var n of fibGen(20) {

 console.log(n)

}

無限序列

因為可以懶賦值,那麼可能表演一些Haskell招數, 類似infinite sequences. 這裡能夠yield一個無限序列的數量。

function* fibGen () {

 var current = 0, next = 1, swap

 while (true) {

  swap = current, current = next

  next = swap + next

  yield current

 }

}

我們來看看一個斐波那契數流的懶賦值,要求它回傳5000以後的第一個斐波那契數:

for (var num of fibGen()) {

 if (num > 5000) break

}

console.log(num) // 6765

非同步流程控制

使用generators實現非同步流程控制,最常見是各種 promise庫包,那麼它是如何運作呢?

在Node領域,每個事情都和回呼有關,這是我們的低層次異步功能,我們可以使用generators 建立一個通訊通道,從而使用同步編程的風格編寫非同步程式碼。

run(function* () {

 console.log("Starting")

 var file = yield readFile("./async.js") // [1]

 console.log(file.toString())

})

註1表示程式會在等待async.js回傳結果以後再繼續。

genify是一個將generators帶入平常程式設計環境的框架,使用如下:

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函数,它使用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詳解就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持腳本之家。

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn