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: jinksgen.next().value//input name is: jinksgen.next().value
CO
- co的根本目的:将异步操作跟在yield后面,当异步操作完成并返回结果后,再触发下一次next() 。跟在yield后面的异步操作需要遵循一定的规范thunks和 promises
//简化版coconst 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)})