Thunk函数是什么?

1,024 阅读3分钟

这是我参与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+1thunk函数替代了。

这就是 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的问题了?

这么以来和之前所学的内容就串起来了。

觉得写的不错的就点个👍,关注一下呗