【问题标题】:Can't grasp timing of callbacks [duplicate]无法掌握回调的时间[重复]
【发布时间】:2013-11-08 20:03:37
【问题描述】:

我知道这已经被问过一百万次了,但我真的试图分解异步 Javascript 函数和回调,而它只是没有点击。我正在查看 Max Ogden 的节点艺术示例,它是这样的:

var fs = require('fs')
var myNumber = undefined

function addOne(callback) {
  fs.readFile('number.txt', function doneReading(err, fileContents) {
    myNumber = parseInt(fileContents)
    myNumber++
    callback()
  })
}

function logMyNumber() {
  console.log(myNumber)
}

addOne(logMyNumber)

分解一下,我知道当调用 addOne 时,它​​首先启动 fs.ReadFile,这可能需要一些时间才能完成。

我不明白的是,代码不会继续callback() 并执行logMyNumber(在添加myNumber 之前)吗?是什么阻止了callback() 在它应该运行之前运行,这就是重点?或者callback() 不会在doneReading 发生之前发生?我们是否应该假设doneReading 将在fs.readFile“完成”时被调用?

感谢大家耐心帮助我解决这个非常常见的问题:)

【问题讨论】:

  • callback()doneReading 调用,它本身就是一个回调。依赖分号插入的嘘声。
  • @Adam 虽然它实际上并没有在读取文件时调用该函数,不是吗?
  • @JarrodRoberson 所以它暗示了这一点,但就个人而言,我不会认为它特别明确。当某人发脾气时,直言不讳实际上是有帮助的。
  • 我认为文档的问题比示例的问题要小。我碰巧需要一个明确的提醒 doneReading 是回调。我凭经验知道它一定是回调。有道理?我想每个人的学习方式都不一样。

标签: javascript node.js callback


【解决方案1】:

"我们是否应该假设当 fs.readFile 为 "done" 时会调用 doneReading?"

你不必假设它,你可以很确定它。 您可以使用日志记录来查看代码的执行方式和执行顺序。

var fs = require('fs')

console.log("starting script");
console.log("message 1");
function addOne(callback) {
  fs.readFile('number.txt', function doneReading(err, fileContents) {
    console.log("finished loading the file");
    console.log("message 2");
    callback()
  })
}
console.log("message 3");
//logMyNumber will be called after file has read
function logMyNumber() {
  console.log("message 4");
}
console.log("message 5");
addOne(logMyNumber)
console.log("message 6");

//_____________ em>_ 理解异步行为的更简单方法是使用所有熟悉的计时器

console.log("message 1");
var num = 2;

function something() {
    console.log("message 2");
}
function somethingElse() {
    console.log("message 3");
}
console.log("message 4");

setTimeout(something, 1000);
console.log("message 5");
setTimeout(somethingElse, 500);

//代码将运行 1 - 4 - 5 - 3- 2 而不是从上到下,这样就很明显了。 //在文件中读取相同的原因

【讨论】:

    【解决方案2】:

    这是代码的流动方式:

    1. 您调用的 addOne(logMyNumber) 将被执行。
    2. addOne 会读取一个文件,一旦文件被读取它就会
    3. 执行“doneReading”函数中的代码,该函数将调用您的回调(即 logMyNumber)

    【讨论】:

      【解决方案3】:

      看到fs.readFile 的第二个参数了吗?这是一个名为doneReading的函数。

      fs.readFile 只会在完成读取文件后执行doneReading。当doneReading被执行时,最后一行是调用callback(),在这种情况下是对logMyNumber函数的引用。

      【讨论】:

      • 所以fs.readFile() 末尾的某处是doneReading(),它本身就是一个回调,对吗?
      • 是的,在fs.readFile() 的末尾,有一行代码表示执行第二个参数。在这种情况下,第二个参数是一个名为doneReading() 的函数。这就是回调。
      【解决方案4】:

      fs.readFile 将调用给定的回调,即。阅读完成后在您的代码中完成阅读。这就是 Node.js 通常使用回调的方式:您提供在完成异步操作后运行的回调。

      【讨论】:

        【解决方案5】:
        // callback is a parameter to addOne
        // callback is a function, but functions are just objects in javascript
        // so the addOne function just knows that it has one parameter, not that
        // callback is a function
        function addOne(callback) {
        
          // callback is now captured in the closure for the doneReading function
          fs.readFile('number.txt', function doneReading(err, fileContents) {
            myNumber = parseInt(fileContents)
            myNumber++
        
            // callback is executed here
            // But we are inside the doneReading function
            // which is itself a callback to the fs.readFile function
            // therefore, it does not get executed until the file has finished reading
            callback()
          })
        }
        
        // similarly, logMyNumber has not been called, it has just been defined
        // as a function (object)...
        function logMyNumber() {
          console.log(myNumber)
        }
        
        // ...and passing logMyNumber to addOne here does not execute it
        addOne(logMyNumber)
        

        这样就解决了吗?

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-10-07
          • 2019-07-28
          • 2018-04-25
          • 1970-01-01
          • 2011-05-29
          • 1970-01-01
          • 2012-03-31
          • 1970-01-01
          相关资源
          最近更新 更多