Asynchronous constructor Asynchronous constructor node.js node.js

Asynchronous constructor


Update 2:Here is an updated example using an asynchronous factory method. N.B. this requires Node 8 or Babel if run in a browser.

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();

Update:The code below got upvoted a couple of times. However I find this approach using a static method much better:https://stackoverflow.com/a/24686979/2124586

ES6 version using promises

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)        });    }}//Usagenew Element().then(function(instance){    // do stuff with your instance});


Given the necessity to avoid blocking in Node, the use of events or callbacks isn't so strange(1).

With a slight edit of Two, you could merge it with 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.}...

Though, like the fs.readFile in your example, the core Node APIs (at least) often follow the pattern of static functions that expose the instance when the data is ready:

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) It shouldn't take very long to read a JSON file. If it is, perhaps a change in storage system is in order for the data.


I have developed an async constructor:

function Myclass(){ return (async () => {     ... code here ...     return this; })();}(async function() {  let s=await new Myclass(); console.log("s",s)})();
  • async returns a promise
  • arrow functions pass 'this' as is
  • it is possible to return something else when doing new (you still get a new empty object in this variable. if you call the function without new. you get the original this. like maybe window or global or its holding object).
  • it is possible to return the return value of called async function using await.
  • to use await in normal code, need to wrap the calls with an async anonymous function, that is called instantly. (the called function returns promise and code continues)

my 1st iteration was:

maybe just add a callback

call an anonymous async function, then call the callback.

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

my 2nd iteration was:

let's try with a promise instead of a callback. I thought to myself: strange a promise returning a promise, and it worked. .. so the next version is just a promise.

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-based for old javascript

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