有人能解释nodejs中回调的这种行为吗?

时间:2016-09-01 08:10:52

标签: node.js callback

我在nodejs中尝试了这段代码:

var fs = require('fs-extra');

console.log("-- line 1 --");

fs.ensureDir('./abc', function (err) {
  if (!err) console.log("-- ensured --");
});

fs.copy("./sample", "./myFolder/samps", function (err) {
  if (err)  return console.error("sample to myFolder failed"); // sample is a file
  console.log("-- copied --");
});

fs.readdir("./myFolder", function (err, files) {
  if (err)  return console.error("-- read my dir --");
  files.forEach( function (file) {
    console.log(file);
  });
  console.log("-- my folder done --");
});

console.log("-- line 2 --");

我得到的输出是:

-- line 1 --
-- line 2 --
  ....
list of files -> doesn't include the newly copied "samps" file
  ....
-- my folder done --
-- ensured --
-- copied --

现在我的问题是,回调执行的顺序不应该是我编写它们的顺序 - 也就是说,不应该是这样 - 确保,复制,文件列表和myFolder完成了

现在下一个让我感到困惑的是

var fs = require('fs-extra');

console.log("-- line 1 --");

fs.ensureDir('./abc', function (err) {
  if (!err) console.log("-- ensured --");
});

fs.copy("./sample", "./myFolder/samps", function (err) {
  if (err)  return console.error("sample to myFolder failed"); // sample is a file
  console.log("-- copied --");
});

fs.readdir("./", function (err, files) {
  if (err)  return console.error("-- read root dir --");
  files.forEach( function (file) {
    console.log(file);
  });
  console.log("-- root dir done --");
});

console.log("-- line 2 --");

输出:

-- line 1 --
-- line 2 --
-- ensured --
   ....
list of files and directories -> includes the newly created "abc" directory
   ....
-- root dir done --
-- copied --

我不明白在文件列表之前是如何打印确保,但在前一种情况下不是,为什么已复制总是在最后打印出来?

如何在列表中创建 abc ,但 samps 是否包含在上一个中?

有人可以解释一下这种行为吗?

4 个答案:

答案 0 :(得分:1)

文件系统请求(不是来自具有'同步'后缀的方法)在线程池中执行,因此所有3个请求将并行执行。因此,由于各种因素(例如磁盘状态,操作系统调度等),您无法对这些请求的完成顺序做出任何假设。

如果您需要确保订单,则需要使用第三方async模块,Promises等链接请求。

答案 1 :(得分:1)

Look nodejs是一种异步语言,它永远不会在其单个主线程上等待任何输入输出。

因此,在代码中执行行的顺序将类似于下面提到的顺序。 1,2,3,4,5。 随着2,3,4的执行,将在nodejs中注册回调,这将在收到相应功能的响应时执行。现在功能响应的顺序可能取决于多个因素(CPU使用率,磁盘可用性等),并且将取决于执行该操作所需的执行时间。

   1. console.log("-- line 1 --");

   2. fs.ensureDir('./abc', function (err) {
      if (!err) console.log("-- ensured --");
    });

   3. fs.copy("./sample", "./myFolder/samps", function (err) {
      if (err)  return console.error("sample to myFolder failed"); // sample is a file
      console.log("-- copied --");
    });

   4. fs.readdir("./myFolder", function (err, files) {
      if (err)  return console.error("-- read my dir --");
      files.forEach( function (file) {
        console.log(file);
      });
      console.log("-- my folder done --");
    });

   5. console.log("-- line 2 --");

答案 2 :(得分:0)

fs-extra 模块,就像核心 fs 模块一样提供两种功能

  • 同步(例如 ensureDirSync
  • 异步(例如 ensureDir

在同步的情况下,执行线程会阻塞,直到函数完成,然后才能进行下一次调用。因此,函数将被执行并完成它们被调用的顺序。 在异步情况下,无法控制它们完成执行的顺序并触发回调以登录到控制台。

您正在使用函数的异步,非阻塞版本。因此,订单不会被保留。

查看fs-extra module

的文档

答案 3 :(得分:0)

您对fs的调用已将执行放入池中。您无权访问该池,也无法知道它将如何以及何时执行它。

这是怎么回事:

| Node.js thread                | Pool                              |
| ----------------------------- | --------------------------------- |
| import fs                     |                                   |
| Print "-- line 1 --"          |                                   |
| Start fs.ensureDir            | fs.ensureDir                      |
| Start fs.copy                 | fs.ensureDir, fs.copy             |
| Start fs.readdir              | fs.ensureDir, fs.copy, fs.readdir |
| Print "-- line 2 --"          | fs.ensureDir, fs.copy, fs.readdir |
|                               | fs.copy, fs.readdir               |
| Print "-- ensured --"         | fs.copy, fs.readdir               |
|                               | fs.copy                           |
| Print "-- copied --"          | fs.copy                           |
|                               |                                   |
| Print "-- root dir done --"   |                                   |

如果您希望按照预期的顺序进行调用,则必须告诉node.js等待fs执行结束,然后才能继续:

var fs = require('fs-extra');

console.log('-- line 1 --');

fs.ensureDir('./abc', function (err) {
    if (!err) console.log('-- ensured --');
    fs.copy('./sample', './myFolder/samps', function (err) {
        if (err)  return console.error('sample to myFolder failed'); // sample is a file
        console.log('-- copied --');
        fs.readdir('./', function (err, files) {
            if (err)  return console.error('-- read root dir --');
            files.forEach( function (file) {
                console.log(file);
            });
            console.log('-- root dir done --');
            console.log('-- line 2 --');
        });
    });
});

或者:

'use strict';

var async = require('async'),
    fs = require('fs-extra');

async.series([
    (callback) => {
        console.log('-- line 1 --');
        callback();
    },
    (callback) => {
        fs.ensureDir('./abc', function (err) {
            if (!err) console.log('-- ensured --');
            callback();
        });
    },
    (callback) => {
        fs.copy('./sample', './myFolder/samps', function (err) {
            if (err) {
                callback('sample to myFolder failed');
            }
            console.log('-- copied --');
            callback();
        });
    },
    (callback) => {
        fs.readdir('./', function (err, files) {
            if (err) {
                callback('-- read root dir --');
            }
            files.forEach( function (file) {
                console.log(file);
            });
            console.log('-- root dir done --');
        });
    }
], (error) => {
    if(error) {
        console.error(error);
    }
    console.log('-- line 2 --');
});