我跟随Kyle Simpson Rethinking Asynchronous JavaScript视频课程,并对他的thunk模式如何使用闭包感到困惑。代码是这样的:
function ajax(url, cb) {
$.ajax({ url: `text/${url}`, type: 'GET', dataType: 'json' })
.done(data => {
cb(data)
})
}
function getFile(file) {
var text, fn;
ajax(file,function(response){
if (fn) {
fn(response)
} else {
text = response
}
})
return function th(cb) {
if (text) {
cb(text)
} else {
fn = cb
}
}
}
var th1 = getFile('1')
var th2 = getFile('2')
var th3 = getFile('3')
th1(function ready(text){
console.log(text)
th2(function ready(text){
console.log(text)
th3(function ready(text){
console.log(text)
th2(function (text) {
console.log(text)
})
})
})
})
我在最后的嵌套部分添加了对th2
的额外调用。我期望使用闭包来返回最初从th2
打印的值,存储在text
函数中的闭包变量getFile
中,即不进行另一次网络调用。虽然事实并非如此:在t3
回调中打印文本后执行停止。
答案 0 :(得分:0)
我期望使用闭包来返回最初从
th2
打印的值,该值存储在text
函数中的闭包变量getFile
中。虽然事实并非如此:在t3
回调中打印文本后执行停止。
这些thunk的问题是你不能使用它们两次(至少,当第一次使用是异步时)。该值永远不会存储在闭包变量text
中。为什么?因为th2
是在ajax调用成功之前第一次运行的,它运行了
if (text) // still empty
…
else // nope, nothing yet, store for later
fn = cb
然后,当ajax
调用回调时,它只会运行
if (fn) // we got something to call
fn(response)
…
而不是text = response
。因此,当第二次调用th2
时(或者更糟糕的是,立即从回调中调用),它将再次尝试将cb
存储在fn
变量中,但什么都不会叫那个。
可能的解决方法是
… // in the thunk closure
ajax(file, function(response) {
text = response;
if (fn) {
fn(response)
}
})
相反会使你的代码工作,但仍然会被破坏:如果在异步th2
回调之前多次调用ajax
会怎么样?然后cb
覆盖先前的fn
,因此最终我们需要维护一系列应该调用的回调。好吧,这样做并为回调添加可链接性,并且you've got the most basic Promise implementation已经。