Node.js的模块的初始化异步 [英] Asynchronous initialization of Node.js module

查看:122
本文介绍了Node.js的模块的初始化异步的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想以异步方式初始化模块,并拿出几个想法。我需要从蒙戈集合和其他数据列表DB对象,但是文件列表中的 ./ 将为了简便起见做的。

I'd like to initialize module in asynchronous way and come up with couple of ideas. I need DB object with list of collections from Mongo and other data, but list of files in ./ will do for brevity.

因为我需要我无法导出函数或类要求(DB)返回同一个对象每次。

I can't export function or class because I need require('db') to return same object everytime.

首页并最简单的一种东西来到我的脑海里是分配 module.exports 对象后来填充它:

First and simplest what came to my mind is to assign module.exports to Object and populate it later:

var exports = {};
module.exports = exports;

require('fs').readdir('.', function(err, files) {
  exports.error = err;
  exports.files = files;
});

坏事 - 我真的不从外面知道清单准备好,并检查错误没有什么好办法

Bad thing — I don't really know from outside when list is ready and no good way to check for errors.

办法我已经COMED了将继承 EventEmitter ,并通知大家,DB是准备或发生错误。如果一切正常 - 继续前进

Second way I've comed up with is to inherit EventEmitter and notify everyone that DB is ready or error occured. If everything ok - keep going.

var events = require('events');
var util = require('util');

function Db() {
  events.EventEmitter.call(this);
  this.ready = false;
  this.files = null;
  this.initialize();
}

util.inherits(Db, events.EventEmitter);

Db.prototype.initialize = function() {
  if (this.ready)
    return this.emit('ready');

  var self = this;
  require('fs').readdir('.', function(err, files) {
    if (err)
      return self.emit('error', err);

    self.files = files;
    self.ready = true;
    self.emit('ready');
  });
};

module.exports = new Db();


立即我认为这是比较合理的:


And now I think that's more reasonable:

// db.js
var exports = {init: init};
module.exports = exports;

function init(callback) {
  callback = (typeof callback === 'function') ? callback : function() {};
  require('fs').readdir('.', function(err, files) {
    delete exports.init;
    exports.result = files; // that's pretty much what I need,
                            // so don't mind result slightly differs
                            // from previous cases
    callback(err);
  });
}

// main.js
var db = require('./db');

// check for `db.init` presence maybe...

db.init(function(err) {
  return err ? console.error('Bad!')
             : console.log(db); // It works!
});


我应该怎么挑,为什么?如何坏,一般这样的想法和我特别选择?


What should I pick and why? How bad is such idea in general and my options in particular?

感谢您的反馈意见。

推荐答案

TL; DR:使用 readdirSync()而不是 READDIR()如果你只是打算在启动时读取本地文件。如果你计划实际上是从远程数据库中读取数据,或者在运行时做任何I / O,使用选项#2 - 回调。解释和$ C低于$ C的例子。

TL;DR: Use readdirSync() instead of readdir() if you're just planning to read local files at startup time. If you're planning to actually read data from remote database or do any I/O at runtime, use your option #2 - the callback. Explanation and code examples below.

详细说明:

虽然起初这似乎是一个模块/ dependecy /要求相关的问题,它真的不是。它的如何处理的异步code通用的问题。让我来解释一下:

While at first this might seem like a module/dependecy/require-related question, it's really not. It's a generic question of how to handle asynchronous code. Let me explain:

要求()基本上是唯一的同步的功能在整个与我交易节点​​广泛应用于/ O(它需要从文件系统其他模块) 。同步意味着它实际上返回它的数据作为返回值,而不是调用回调。

require() is basically the only synchronous function widely used throughout node that deals with I/O (it requires other modules from filesystem). Synchronous means it actually returns it's data as return value, instead of calling a callback.

在异步编程最基本的101规则是:

The most basic 101 rule in asynchronous programming is:

您可以绝不会采取异步件code,并为它创建一个同步API。

You can never take an asynchronous piece of code and create a synchronous API for it.

要求使用了一种特殊的同步 <$ C READFILE 的版本,称为$ C > readFileSync 。因为模块实际上只装在节目的开始,事实上,它阻止,而它的读取模块Node.js的执行是没有问题的。

require uses a special synchronous version of readFile called readFileSync. Since modules are really only loaded at the start of the program, the fact that it blocks the node.js execution while it's reading the module is not a problem.

在你的榜样然而,试图执行额外的异步I / O - READDIR()期间需要完成的阶段。因此,你要么需要使用同步此命令的版本或API需要改变...

In your example however, you try to perform additional asynchronous I/O - readdir() done during the require stage. Thus, you either need to use synchronous version of this command or the API needs to change...

因此​​,有背景,以您的问题。

So there's the background to your problem.

您确定了两个基本选项:

You identified the two basic options:


  1. 使用的的(这是本质上是相同的 EventEmitter 为例)

  2. 使用的回调的(你的第二个例子显示了这口井)
    和第三的是:

  3. 使用的同步叫做 READDIR()命令版本 readdirSync()

  1. using a promise (which is essentially the same as your EventEmitter example)
  2. using a callback (your second example shows this well) and a third is:
  3. using a synchronous version of the readdir() command called readdirSync()

我会使用选项#3 为简单的原因 - 但只有当你打算在启动时刚读一对夫妇的文件,你的榜样暗示。如果您以后DB模块实际上是要连接到一个数据库 - 或者,如果你打算做任何这在运行,现在跳船和异步API去

I would use the option #3 for simplicity reason - but only if you're planning to just read a couple files at startup time as your example implies. If later your DB module is actually going to connect to a database - or if you're planning to do any of this at runtime, jump the boat now and go with async API.

没有多少人记得这个了,但承诺实际上是如何处理在node.js中异步原来的默认在节点0.1.30然而promisses被取出,并通过与函数的标准回调取代 (错了,结果)签名。这是为简单的原因主要是完成的。

Not many people remember this anymore, but promises were actually the original default of how to handle async in node.js. In node 0.1.30 however promisses were removed and replaced by a standardized callback with the function(err, result) signature. This was done largely for simplicity reasons.

这几天,绝大多数的异步调用的需要这个标准的回调作为最后一个参数。你的数据库驱动程序这样做,你的web框架做它 - 它无处不在。你应该留在prevalent设计和使用它。

These days, vast majority of your async calls takes this standard callback as the last parameter. Your database driver does it, your web framework does it - it's everywhere. You should stay with the prevalent design and use it too.

的唯一原因preFER承诺或事件,如果你有多个不同的结果,可以发生。例如,一个插座可以打开,接收数据,关闭,冲洗等。

The only reason to prefer promises or events is if you have multiple different results that can happen. For example a socket can be opened, receive data, be closed, flushed etc.

这是不是你的情况。你的模块始终不相同(读取一些文件)。所以选项#2 这是(除非你能留下来的同步)。

This is not your case. Your module always does the same (reads some files). So option #2 it is (unless you can stay synchronous).

最后,这里有两个选项获胜稍微改写:

Finally, here are the two winning options rewritten slightly:

同步选项:结果
好只是在启动时本地文件系统

// db.js
var fs = require('fs');
exports = fs.readdirSync('.');

// main.js
var db = require('./db');
// insert rest of your main.js code here

异步选项:结果
当你想使用的数据块等。

// db.js
var fs = require('fs'), cached_files;

exports.init = function(callback) {
  if (cached_files) {
    callback(null, cached_files);
  } else {
    fs.readdir('.', function(err, files) {
      if (!err) {
        cached_files = files;
      }
      callback(err, files);
    });
  }
};

// main.js
require('./db').init(function(err, files) {
  // insert rest of your main.js code here
});

这篇关于Node.js的模块的初始化异步的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆