asynchronous构造函数

我怎样才能最好地处理以下情况?

我有一个构造函数需要一段时间才能完成。

var Element = function Element(name){ this.name = name; this.nucleus = {}; this.load_nucleus(name); // This might take a second. } var oxygen = new Element('oxygen'); console.log(oxygen.nucleus); // Returns {}, because load_nucleus hasn't finished. 

我看到三个选项,每个选项都与众不同。

,给构造函数添加一个callback。

 var Element = function Element(name, fn){ this.name = name; this.nucleus = {}; this.load_nucleus(name, function(){ fn(); // Now continue. }); } Element.prototype.load_nucleus(name, fn){ fs.readFile(name+'.json', function(err, data) { this.nucleus = JSON.parse(data); fn(); }); } var oxygen = new Element('oxygen', function(){ console.log(oxygen.nucleus); }); 

,使用EventEmitter发射一个“加载”事件。

 var Element = function Element(name){ this.name = name; this.nucleus = {}; this.load_nucleus(name); // This might take a second. } Element.prototype.load_nucleus(name){ var self = this; fs.readFile(name+'.json', function(err, data) { self.nucleus = JSON.parse(data); self.emit('loaded'); }); } util.inherits(Element, events.EventEmitter); var oxygen = new Element('oxygen'); oxygen.once('loaded', function(){ console.log(this.nucleus); }); 

或三 ,阻止构造函数。

 var Element = function Element(name){ this.name = name; this.nucleus = {}; this.load_nucleus(name); // This might take a second. } Element.prototype.load_nucleus(name, fn){ this.nucleus = JSON.parse(fs.readFileSync(name+'.json')); } var oxygen = new Element('oxygen'); console.log(oxygen.nucleus) 

但是我从来没有见过这样做过。

我还有什么其他的select?

鉴于在Node中避免阻塞的必要性,使用事件或callback并不是很奇怪(1)

稍微修改两个,你可以把它和One合并:

 var Element = function Element(name, fn){ this.name = name; this.nucleus = {}; if (fn) this.on('loaded', fn); this.load_nucleus(name); // This might take a second. } ... 

虽然,就像在你的例子中的fs.readFile一样,核心Node API(至less)经常遵循静态函数的模式,在数据准备就绪的时候公开实例:

 var Element = function Element(name, nucleus) { this.name = name; this.nucleus = nucleus; }; Element.create = function (name, fn) { fs.readFile(name+'.json', function(err, data) { var nucleus = err ? null : JSON.parse(data); fn(err, new Element(name, nucleus)); }); }; Element.create('oxygen', function (err, elem) { if (!err) { console.log(elem.name, elem.nucleus); } }); 

(1)读取JSON文件不需要很长时间。 如果是这样,也许存储系统的变化是为了数据。

更新2:这是使用asynchronous工厂方法的更新示例。 注意,如果在浏览器中运行,则需要节点8或Babel。

 class Element { constructor(nucleus){ this.nucleus = nucleus; } static async createElement(){ const nucleus = await this.loadNucleus(); return new Element(nucleus); } static async loadNucleus(){ // do something async here and return it return 10; } } async function main(){ const element = await Element.createElement(); // use your element } main(); 

更新:下面的代码被提了几次。 不过,我发现这种方法使用更好的静态方法: https : //stackoverflow.com/a/24686979/2124586

ES6版本使用承诺

 class Element{ constructor(){ this.some_property = 5; this.nucleus; return new Promise((resolve) => { this.load_nucleus().then((nucleus) => { this.nucleus = nucleus; resolve(this); }); }); } load_nucleus(){ return new Promise((resolve) => { setTimeout(() => resolve(10), 1000) }); } } //Usage new Element().then(function(instance){ // do stuff with your instance }); 

你可以做的一件事是预先加载所有的primefaces核(可能效率低下,我不知道它有多less数据)。 另一个,我会build议如果预加载不是一个选项,将涉及一个cachingcallback,以保存加载核。 这是这种方法:

 Element.nuclei = {}; Element.prototype.load_nucleus = function(name, fn){ if ( name in Element.nuclei ) { this.nucleus = Element.nuclei[name]; return fn(); } fs.readFile(name+'.json', function(err, data) { this.nucleus = Element.nuclei[name] = JSON.parse(data); fn(); }); } 

这是一个糟糕的代码devise。

主要的问题是在callback你的实例它不是仍然执行“返回”,这是我的意思

 var MyClass = function(cb) { doAsync(function(err) { cb(err) } return { method1: function() { }, method2: function() { } } } var _my = new MyClass(function(err) { console.log('instance', _my) // < _my is still undefined // _my.method1() can't run any methods from _my instance }) _my.method1() // < it run the function, but it's not yet inited 

所以,好的代码devise是在实例化类之后显式调用“init”方法(或者在你的情况下是“load_nucleus”)

 var MyClass = function() { return { init: function(cb) { doAsync(function(err) { cb(err) } }, method1: function() { }, method2: function() { } } } var _my = new MyClass() _my.init(function(err) { if(err) { console.error('init error', err) return } console.log('inited') // _my.method1() }) 

我开发了一个asynchronous构造函数:

 function Myclass(){ return (async () => { ... code here ... return this; })(); } (async function() { let s=await new Myclass(); console.log("s",s) })(); 
  • asynchronous返回一个承诺
  • 箭头函数按原样传递“this”
  • 作为被调用的asynchronous函数的返回,可能会返回一个值作为await的结果。
  • 新的时候可能会返回其他的东西。
  • 在正常的代码中使用await,需要用asynchronous匿名函数来包装调用,即时调用。 (被调用的函数返回promise,代码继续)

我的第一个迭代是:

也许只是添加一个callback

调用匿名asynchronous函数,然后调用callback函数。

 function Myclass(cb){ var asynccode=(async () => { await this.something1(); console.log(this.result) })(); if(cb) asynccode.then(cb.bind(this)) } 

我的第二个迭代是:

让我们尝试一个承诺,而不是callback。 我心想:奇怪的一个承诺回复了一个承诺,它的工作。 ..所以下一个版本只是一个承诺。

 function Myclass(){ this.result=false; var asynccode=(async () => { await new Promise (resolve => setTimeout (()=>{this.result="ok";resolve()}, 1000)) console.log(this.result) return this; })(); return asynccode; } (async function() { let s=await new Myclass(); console.log("s",s) })(); 

基于callback的旧的JavaScript

 function Myclass(cb){ var that=this; var cb_wrap=function(data){that.data=data;cb(that)} getdata(cb_wrap) } new Myclass(function(s){ }); 

你可以通过nsynjs同步运行构造函数。 下面是一个例子来说明:

index.js(主要的应用程序逻辑):

 var nsynjs = require('nsynjs'); var modules = { MyObject: require('./MyObject') }; function synchronousApp(modules) { try { var myObjectInstance1 = new modules.MyObject('data1.json'); var myObjectInstance2 = new modules.MyObject('data2.json'); console.log(myObjectInstance1.getData()); console.log(myObjectInstance2.getData()); } catch (e) { console.log("Error",e); } } nsynjs.run(synchronousApp,null,modules,function () { console.log('done'); }); 

MyObject.js(具有慢构造函数的类定义):

 var nsynjs = require('nsynjs'); var synchronousCode = function (wrappers) { var config; // constructor of MyObject var MyObject = function(fileName) { this.data = JSON.parse(wrappers.readFile(nsynjsCtx, fileName).data); }; MyObject.prototype.getData = function () { return this.data; }; return MyObject; }; var wrappers = require('./wrappers'); nsynjs.run(synchronousCode,{},wrappers,function (m) { module.exports = m; }); 

wrappers.js(感知nsynjs的慢速函数封装):

 var fs=require('fs'); exports.readFile = function (ctx,name) { var res={}; fs.readFile( name, "utf8", function( error , configText ){ if( error ) res.error = error; res.data = configText; ctx.resume(error); } ); return res; }; exports.readFile.nsynjsHasCallback = true; 

这个例子的全套文件可以在这里find: https : //github.com/amaksr/nsynjs/tree/master/examples/node-async-constructor