0

我正在关注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,存储在函数的闭包变量textgetFile,即不会进行另一个网络调用。虽然这不是发生的事情:在t3回调中打印文本后执行停止。

为什么这个闭包不返回它已经检索到的值?

4

1 回答 1

0

我希望这种闭包的使用能够返回最初从 打印的值th2,存储在函数的闭包变量textgetFile。虽然这不是发生的事情:在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稍后第二次调用时(或者,更糟糕的是,立即从回调中调用),它将再次尝试将 存储cbfn变量中,但不会调用它。


一个可能的解决方法是

… // in the thunk closure
ajax(file, function(response) {
  text = response;
  if (fn) {
    fn(response)
  }
})

相反,这将使您的代码工作,但仍然被破坏:如果在异步回调th2之前多次调用怎么办?ajax然后cb覆盖前一个fn,所以最终我们需要维护一个回调数组,所有这些都应该被调用。好吧,这样做并为回调添加可链接性,您已经拥有了最基本的 Promise 实现

于 2017-08-10T02:09:45.220 回答