【问题标题】:Why is this fs.readFile loop not pushing its results to my array? [duplicate]为什么这个 fs.readFile 循环没有将其结果推送到我的数组? [复制]
【发布时间】:2015-05-17 01:41:30
【问题描述】:
#!/usr/bin/env node

var fs = require('fs')
  , async = require('async') 
  , program = require('commander')

program
  .version('0.0.1')
  .usage('<keywords>')
  .parse(process.argv)

async.waterfall([
  fs.readdir.bind(fs, __dirname),
  parseHTML,
], saveResult)

function parseHTML(files, callback) {
  var result = []

  files.forEach(function(file) {
    if (file.match(/\.html$/)) {
      fs.readFile(file, 'utf8', function(err, data) {
        if (err) throw err
        result.push(data)
      })
    }
  })

  callback(null, result)
}

function saveResult(err, result) {
  console.log(result)
}

我很困惑,因为console.log(data) 确实输出了数据:

<p>File 1</p>

<p>File 2</p>

然而最后的 result 是一个空数组:[]

为什么我做错了?

【问题讨论】:

标签: javascript node.js fs


【解决方案1】:

您必须等到最后一个fs.readFile() 操作完成后才能查看结果。这些是异步操作,它们会在未来一段时间内完成。您正在检查任何结果之前的结果。

有很多方法可以解决这个问题,但这种方法可能会对您的代码造成最少的更改,因为它只是记录已完成的数量:

function parseHTML(files, callback) {
    var result = [],
        cntr = 0;

    files.forEach(function(file) {
        if (file.match(/\.html$/)) {
            fs.readFile(file, 'utf8', function(err, data) {
                if (err) throw err
                result.push(data)
                    // see if we're done processing all the results
                    ++cntr;
                if (cntr === files.length) {
                    callback(null, result);
                }
            });
        } else {
            ++cntr;
            if (cntr === files.length) {
                callback(null, result);
            }
        }
    });
}

我个人更喜欢使用 Promise 和 Promise.all() 来解决这个问题。

这是一个使用 Bluebird Promise 库的版本,它保留了您的一些其他结构:

var Promise = require("bluebird");
var fs = Promise.promisifyAll(require('fs'));

// your other code here

function parseHTML(files, callback) {
    var promises = [];

    files.forEach(function(file) {
        if (file.match(/\.html$/)) {
            promises.push(fs.readFileAsync(file, 'utf8'));
    });
    Promise.all(promises).then(function(results) {
        // all results in results array
        callback(null, results);
    }, function(err) {
       // error here
    });
}

而且,这是一个完全承诺的版本:

var Promise = require("bluebird");
var fs = Promise.promisifyAll(require('fs'));

function parseHTML(files) {
    var promises = [];

    files.forEach(function(file) {
        if (file.match(/\.html$/)) {
            promises.push(fs.readFileAsync(file, 'utf8'));
    });
    return Promise.all(promises);
}

fs.readdirAsync(__dirname).then(parseHTML).then(function(results) {
    // files are in the results array here
}).catch(function(err) {
    // error here
});

【讨论】:

  • 嘿,我正在研究的代码呢,哈。
  • @alexchenco - 它回来了。我意识到这是错误的,所以暂时回滚。
  • 谢谢!哇,没想到让代码等待某个任务这么复杂。
  • @alexchenco - 如果你打算在 node.js 中编程,你需要非常熟悉稍后完成的异步操作。 node.js 不等待异步操作。主代码行继续执行,异步操作在一段时间后完成。如果你想根据异步操作的完成来协调一些动作,你必须编写特殊的代码来做到这一点。你可能想学习 Promise,因为它们为此提供了很多工具。您展示的正在使用的异步库也为此提供了工具。
  • @alexchenco - 我在我的答案中添加了一个承诺版本的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-19
  • 2017-04-18
  • 2018-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多