Node7发布后已经可以通过添加--harmony-async-await
的参数调用来直接支持async/await
语法了,据说Node8还会进一步推进其发展,于是研究了一下JS的异步流程控制和下一代Node Web框架Koa2
。
关于generator
async/await
的发展史已有一大堆文章讲过了,这里不再赘述。
tj的co
是Koa2
上个大版本Koa1
的核心,在没有async/await
的时候一般会借助co
来做自动流程控制。关于co
的源码分析文章也有很多,代码不长值得一读,参考了一些分析文章也算是了解了其逻辑和思路。
在co
中出现了一个thunkToPromise
的函数,一些文章都跳过了这个并表示thunk
函数已经没什么意义了,但本着好奇心读了阮一峰的Thunk 函数的含义和用法,文中一个地方一时没有搞懂,故写此文记录一下。
thunkify
的代码很少,就是一个函数:
1 | function thunkify(fn){ |
Demo:
1 | function f(a, b, callback){ |
让我一时没有搞懂的是为什么借助called
标记能够确保回调函数只执行一次,借助VS Code的断点调试把文中示例的代码跑了一遍总算搞懂了:
Demo中首先真正执行的是thunkify(f)
,f
函数传入thunkify
后直接返回了一个闭包,这里称之为闭包1,闭包1被赋值给了ft,ft即为闭包1的一个引用。
接着执行的是ft(1, 2)
,ft
中传入了(1, 2)
来执行,ft
中将duck type
的伪数组arguments
保存为一个真实数组args
,所以此时args
数组中有两个成员即1
和2
,ft
最后又返回了一个闭包,这里称之为闭包2。
接着执行的是ft(1, 2)(console.log)
,也就是将console.log
传入闭包2来执行,传入的console.log
即形参done
其实就是一开始f
的回调函数,这时候重点来了,在闭包2中增加了一个标记called
来记录回调是否执行过一次了,而push
进args
数组的函数则已经不是单纯的回调,而是被包裹了原回调、保证只会执行一次的函数
1 | function(){ |
最后执行的就是fn.apply(ctx, args)
,而thunkify
函数的形参fn
对应的就是一开始传入的f
函数,所以总的看来,真正执行的还是最初的f
函数,而被改变的是传入的回调,回调被包裹了一层,借助called
标记来保证只会被执行一次,执行过后called
标记被改变,不再会被执行。