这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战
前言
最近会看一些源码库,但是经常会看到Thunk函数
,说实话,我是比较陌生的,不太明白这是个什么玩意儿。于是乎抱着彻底搞懂的原则,就去查询了一下。例如在co的源码中,将thunk函数转换成promise。
来源
Thunk函数早在上个世纪60年代就诞生了。
那时,编程语言刚刚起步,计算机学家还在研究,编译器怎么写比较好。一个争论的焦点是"求值策略",即函数的参数到底应该何时求值
怎么理解上面这段话呢?看几个🌰
const x = 1
function a(b) {
return b * 2
}
b(x + 1)
那么请问这个x+1
什么时候执行呢?是传值的时候就计算,还是说使用的时候才计算呢?
1.传值的时候计算
b(x + 1) => b(2)
2.使用的时候才计算
function a(b) {
return (x + 1) * 2 => return 2 * 2
}
如果在传值的时候计算那么可能会造成性能上的浪费。因为可能算好了,没打算用。
function a(b, c) {
return c
}
const x = 1.1
a(x^1999, b)
于是有些人就支持传名调用
,而这个名就成thunk函数
。
Thunk函数
怎么理解上面这段话,show me your code
.
继续使用上个🌰
const x = 1
function a(b) {
return b * 2
}
b(x + 1)
thunk ===>转换
const x = 1
function a(b) {
return b() * 2
}
thunk (x) {
return x + 1
}
b(thunk)
原本的x+1
被thunk
函数替代了。
这就是 Thunk 函数的定义,它是"传名调用"的一种实现策略,用来替换某个表达式。
js中的chunk函数略有不同。不同在哪里呢?
JS中的chunk函数
JS中的chunk函数主要功能是,将多个参数的函数变成,单参数的函数,并且只接受回调函数作为参数。
怎么说,上code
// 正常版本的readFile(多参数版本)
fs.readFile(fileName, callback);
// 单参数版本
var readFileThunk = Thunk(fileName);
readFileThunk(callback);
var Thunk = function (fileName){
return function (callback){
return fs.readFile(fileName, callback);
};
};
上面的单参数版本就是一个chunk函数
。任何函数,只要参数有回调函数,那么都可以写成chunk函数
。
const Thunk = function(fn){
const args = Array.prototype.slice.call(arguments)
return function (cb) {
args.push(cb)
return fn.apply(this, args)
}
}
var readFileThunk = Thunk(fs.readFile);
readFileThunk(fileA)(callback)
thunkify
thunkify这是一个nodejs的库
总结
thunk函数的目的,主要是使得数据和回调分开。
例如:
const fs = require('fs');
const readFile = thunkify(fs.readFile);
//这是执行函数集合
const f1 = readFile('./a.js')
const f2 = readFile('./b.js')
const f3 = readFile('./c.js')
f1((err, data) => {
f2((err, data) => {
f3((err, data) => {
})
})
})
但是上面的嵌套很恶心啊,那么这时候是不是可以使用genrator
函数来改善一下?
function* gen {
const res1 = yield f1()
const res2 = yield f2()
const res3 = yield f3()
}
const val1 = gen().next().value
const val2 = gen().next().value
const val3 = gen().next().value
到了这里是不是我们又可以使用co
来解决需要next
的问题了?
这么以来和之前所学的内容就串起来了。
觉得写的不错的就点个👍,关注一下呗