Node.js模块的异步初始化
我想以异步方式初始化模块,并提出一些想法。我需要具有Mongo集合列表和其他数据的DB对象,但是./
为了简洁起见,其中的文件列表确实有用。
我无法导出函数或类,因为我require('db')
每次都需要返回相同的对象。
想到的最简单的方法是分配module.exports
给Object
它,然后填充它:
var exports = {};module.exports = exports;
require('fs').readdir('.', function(err, files) {
exports.error = err;
exports.files = files;
});
不好的事情–我真的从外面不知道什么时候准备好列表,也没有检查错误的好方法。
方法是继承EventEmitter
并通知所有人数据库已准备就绪或发生了错误。如果一切正常-继续前进。
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();
而 我认为这是比较合理的:
// db.jsvar 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!
});
我应该选择什么,为什么?这种想法总体上有多糟糕,尤其是我的选择有多糟糕?
感谢您的反馈。
回答:
如果打算在启动时读取本地文件,请使用readdirSync()
代替readdir()
。如果您打算实际从远程数据库读取数据或在运行时执行任何I /
O,请使用选项#2-回调。下面的解释和代码示例。
虽然起初这似乎是一个与模块/依赖性/需求相关的问题,但实际上并非如此。这是关于如何处理 的通用问题。让我解释:
require()
从根本上讲,它是唯一一个在整个节点中广泛使用的,处理I / O的
功能(它需要文件系统中的其他模块)。同步意味着它实际上将其数据作为返回值返回,而不是调用回调。
异步编程中最基本的101条规则是:
您 采用异步代码段并为其创建同步API。
require
使用称为的特殊
版本。由于模块实际上仅在程序开始时加载,因此在读取模块时会阻塞node.js执行这一事实不是问题。readFile``readFileSync
在你的榜样然而,试图执行额外的 - readdir()
实现在需要的阶段。因此,您要么需要使用此命令的
版本,要么需要更改API。
因此,存在您问题的背景。
您确定了两个基本选项:
- 使用 承诺 (与
EventEmitter
示例基本相同) - 使用 回调 (第二个示例很好地说明了这一点),第三个是:
- 使用命令的 版本
readdir()``readdirSync()
为了简单起见,我将使用 但仅当您打算在启动时仅读取几个文件时(如您的示例所示)。如果稍后您的数据库模块实际上将要连接到数据库-
或如果您打算在运行时执行任何上述操作,请立即开始并使用异步API。
不再有多少人记得这一点,但是promise实际上是在node.js中处理异步的原始默认设置。但是,在节点0.1.30中,删除了许可并由带有function(err,
result)签名的标准化回调代替。这样做主要是出于简化的原因。
如今,绝大多数异步调用都将标准回调作为最后一个参数。您的数据库驱动程序可以做到,您的Web框架也可以做到-随处可见。您应该保持流行的设计并使用它。
选择诺言或事件的唯一原因是,如果您可能会发生 。例如,可以打开套接字,接收数据,关闭,刷新等。
这不是你的情况。您的模块始终执行相同操作(读取一些文件)。所以 是这样(除非您可以保持 )。
最后,以下是两个稍作重写的制胜法宝:
仅在启动时适合本地文件系统
// db.jsvar fs = require('fs');
exports = fs.readdirSync('.');
// main.js
var db = require('./db');
// insert rest of your main.js code here
用于何时要使用数据库等。
// db.jsvar 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模块的异步初始化 的全部内容, 来源链接: utcz.com/qa/409085.html