【问题标题】:Call to modules in specific order in node在节点中按特定顺序调用模块
【发布时间】:2015-10-01 23:31:04
【问题描述】:

我使用下面的代码调用了两个模块,但是调用操作是在验证文件之前调用的(我在调试中看到过)。我应该做些什么来验证validateFileappHandler.invokeAction 之前被调用?我应该使用承诺吗?

var validator = require('../uti/valid').validateFile();
var appHandler = require('../contr/Handler');
appHandler.invokeAction(req, res);

更新

这是验证文件代码

var called = false;
var glob = require('glob'),
    fs = require('fs');
module.exports = {

    validateFile: function () {

        glob("myfolder/*.json", function (err, files) {
            var stack = [];
            files.forEach(function (file) {
                fs.readFile(file, 'utf8', function (err, data) { // Read each file
                    if (err) {
                        console.log("cannot read the file", err);
                    }
                    var obj = JSON.parse(data);
                    obj.action.forEach(function (crud) {
                        for (var k in crud) {
                            if (_inArray(crud[k].path, stack)) {

                                console.log("duplicate founded!" + crud[k].path);

                                break;
                            }
                            stack.push(crud[k].path);
                        }
                    })
                });
            });
        });
    }
};

【问题讨论】:

  • 这完全取决于validateFile的实现。它会返回一个承诺吗?它是否接受回调作为参数?回答这个问题,你就回答了你的问题。
  • @DenysSéguret - 我可以分享验证文件,请查看我的更新
  • @DenysSéguret - 请查看我的更新代码
  • 所以重点是fs.readFile(file, 'utf8', function (err, data) { // Read each file 这是async 你的validateFile 应该更改为接受回调,并在fs.readFile 的成功回调的最后调用它。
  • @so 在完成所有过程之前如何进行验证?我的意思是invokeAction函数,有办法吗?

标签: javascript node.js promise q bluebird


【解决方案1】:

由于fs.fileReadasync,您应该将要在validateFile 之后执行的代码放到它的callback 中。

来源可能是:

var validator = require('../uti/valid').validateFile();
var appHandler = require('../contr/Handler');
// create a new function that when execute, will call appHandler.invokeAction with req and res given to its arguments.
validator.validateFile(appHandler.invokeAction.bind(null, req, res));

验证器部分应该是:

var called = false;
var glob = require('glob'),
    fs = require('fs');
module.exports = {
    validateFile: function (callback) {

        glob("myfolder/*.json", function (err, files) {
            var stack = [];
            // Use it to decide whether all files processed or not.
            var filesToLoad = files.length;
            files.forEach(function (file) {
                fs.readFile(file, 'utf8', function (err, data) { // Read each file
                    --filesToLoad;
                    if (err) {
                        console.log("cannot read the file", err);
                        // If the invoke action doesn't depend on the result. You may want to call it here too.
                    }
                    var obj = JSON.parse(data);
                    obj.action.forEach(function (crud) {
                        for (var k in crud) {
                            if (_inArray(crud[k].path, stack)) {

                                console.log("duplicate founded!" + crud[k].path);

                                break;
                            }
                            stack.push(crud[k].path);
                        }
                    })

                    // Only called the callback after all files processed.
                    if (filesToLoad === 0) {
                      callback();
                    }

                });
            });
        });
    }
};

编辑:感谢Bergi的提醒,文件是一个数组,当所有文件都处理完后你必须调用回调,所以我们必须进一步使用一个变量来决定有多少文件还没有处理。

【讨论】:

  • 谢谢你认为这比承诺更好吗?非常感谢
  • 我想如果你对promise不熟悉,那么这对理解比较好,但是如果你有时间玩promise的话。诺言的方式对我来说似乎更优雅,IMO。
  • 你不能在循环中调用callback
  • @Bergi 感谢您的通知,已更改代码来处理该问题,介意看看它现在是否有效?
  • 谢谢,现在看起来不错(除了可以改进的错误处理)。现在更明显的是为什么 Promise 是更好的解决方案 :-)
【解决方案2】:

因为globfs.readFile 是异步函数,并且appHandler.invokeAction 在磁盘i/o 期间被调用。

Promise 是解决这个问题的好方法,但老派的回调可以解决这个问题。

validator.validateFile().then(function() {
  appHandler.invokeAction(req, res);
});

用于验证

var Promise = require("bluebird"), // not required if you are using iojs or running node with `--harmony`
    glob = require('mz/glob'),
    fs = require('mz/fs');

module.exports = {
  validateFile: function () {
    return glob("myfolder/*.json").then(function(files) {
      return Promise.all(files.map(function(file) {
        // will return an array of promises, if any of them
        // is rejected, validateFile promise will be rejected
        return fs.readFile(file).then(function (content) {
          // throw new Error(''); if content is not valid
        });
      }));
    })
  }
};

如果您想使用 Promise mz 可能会有所帮助:)

【讨论】:

  • 我喜欢这个,promise看起来比callback的方式漂亮多了,但是看不懂,有什么promise的好教程吗?
  • 谢谢 我应该用它代替 bluebird,它更好吗?提前致谢!
  • 查看你使用的nodejs版本是否支持,iojs从1.0开始支持。来自 Mozilla 开发者网络:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • @jsan - 投了赞成票!能否请您提供如何与蓝鸟一起使用它的示例
  • 谢谢 jsan,为什么我需要 blue bird 和 mz?我不能只用 bulebird 做?如果是,你能提供例子吗?提前谢谢先生!
猜你喜欢
  • 1970-01-01
  • 2023-01-11
  • 1970-01-01
  • 2019-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多