thunk
- 他的發展是由函數的求值策略的分歧決定的,兩種求值策略
- 傳值調用,在進入函數體以前就直接執行完,把值傳進去
- 傳名調用,將表達式傳入函數體,只在用到他的時候求值
- 傳名函數的編譯器實現,其實就是放入一個臨時函數,再將臨時函數傳入函數體,這個臨時函數就叫作thunk函數
- js語言是傳值調用,他的thunk含義有些不一樣,js中,thunk函數替換的不是表達式,而是多參數函數,將它替換成單參數的版本,且只接受回調函數做爲參數
- 任何有回調的函數都是能夠搞成thunk形式的,下面是一個簡單的生成器
var Thunk = function(fn){
return function () {
//先傳入其餘的參數初始化
var args = Array.prototype.slice.call(arguments);
//傳入callback返回的函數
return function(callback){
args.push(callback);
//實際調用的時候
return fn.apply(this,args);
}
}
}
var readFileThunk = Thunk(fs.readFile);
readFileThunk(fileA)(callback);
generator
- Generator是爲JavaScript設計的一種輕量級的協程。它經過yield關鍵字,能夠控制一個函數暫停或者繼續執行generator函數
function * hello (name) {
yield 'your name is: ' + name
return 'input name is: ' + name
}
const gen = hello('jinks')
//your name is: jinks
gen.next().value
//input name is: jinks
gen.next().value
CO
- co的根本目的:將異步操做跟在yield後面,當異步操做完成並返回結果後,再觸發下一次next() 。跟在yield後面的異步操做須要遵循必定的規範thunks和 promises
//簡化版co
const fs = require('fs')
const Q = require('Q')
const readdir = Q.denodeify(fs.readdir)
//或者thunk規範
const thunkify = require('thunkify')
const readdir = thunkify(fs.readdir)
function co(generator) {
return function (fn) {
fn = fn || function () {}
const gen = generator()
function next (err, result) {
if(err) {
return fn(err)
}
const step = gen.next(result)
if(!step.done) {
// thunk
step.value(next)
// promise
step.value.then(res => next(null, res)).catch(err => next(err))
} else {
fn(null, step.value)
}
}
next()
}
}
function *test() {
const result = yield readdir(dir)
}
co(test)((err, result) => {
console.log(err, result)
})