Make JavaScript method wait for constructor to com

2019-07-30 16:57发布

问题:

The constructor takes some time, and when the method is called, this.folders is not yet defined. How do I allow getIt() to wait until the constructor is complete?

function test() {
    var t=this;
    $.getJSON('~.php?task=getFolders&dummy='+new Date().getTime(), function(returned){
        t.folders=returned;
    });
}
test.prototype.getIt = function() {
    return this.folders;
};

var myObj = new test();
console.log(myObj.getIt());

回答1:

Since $.getJSON() is asynchronous, there is no way of preveting test() from returning after t.folders is populated.

You can use a callback:

function test(callback) {
    $.getJSON('~.php?task=getFolders&dummy='+new Date().getTime(), function(returned){
        callback(returned);
    });
}

var myObj = new test(function (folders) {
    console.log(folders);
});

Or a promise (in this example, using Q library):

function test() {
    var t = this;
    t.folders = Q.defer();

    $.getJSON('~.php?task=getFolders&dummy='+new Date().getTime(), function(returned){
        t.folders.resolve(returned);
    });
}
test.prototype.getIt = function() {
    return this.folders.promise;
};

var myObj = new test();
myObj.getIt().done(function (folders) {
    console.log(folders);
});


回答2:

The call is async so you should present a loading spinner and then remove it by populating the data you received.

function test() {
    var t=this;
    //show loading spinner
    $.getJSON('~.php?task=getFolders&dummy='+new Date().getTime(), function(returned){
        t.folders=returned;
//hide loading spinner
//add data to document
    });
}
test.prototype.getIt = function() {
    return this.folders;
};

var myObj = new test();
console.log(myObj.getIt());

If you want to run code after something initializes at some point without including a callback i.e. in your ajax request, one cross browser solution is to constantly check as in the following code,

function runCode(selector,theMethod,timeInMillis){
    if($(selector).length>0){
        theMethod();
    }else{
        setTimeout(function(){runCode(selector,theMethod,timeInMillis);},timeInMillis);
    }
}
runCode('.the-class-of-data',function(){
    console.log(myObj.getIt());
},100);