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)
})