简体   繁体   中英

One function loads before another one is finished

I am programming a website with javascript and skydrive API.

this is my code:

var clientId = '00000000400FFB5A';
var redirectUri = "http://milmantasimmigration.com/skydrive/test/test.html";

WL.init({
    client_id: clientId,
    redirect_uri: redirectUri
});

WL.Event.subscribe("auth.login", onLogin);
WL.Event.subscribe("auth.sessionChange", onSessionChange);

var session;
var companyFolders;
var reportFolders;
var reports;

session = WL.getSession();
if (session) {
    log("You are already signed in!");
    getCompanyFolders();
} else {
    WL.login({
        scope: "wl.signin"
    });
}

function onLogin() {
    var session = WL.getSession();
    if (session) {
        log("You are signed in!");
    }
}

function onLogout() {
    WL.logout();
    log("You are logged out!");
}

function onSessionChange() {
    var session = WL.getSession();
    if (session) {
        log("Your session has changed.");
    }
}

function getCompanyFolders() {
    var getCompanyFoldersDeferred = $.Deferred();

    WL.api({
        path: "/me/skydrive/shared",
        method: "GET"
    }).then(

    function(response) {
        companyFolders = [];
        reportFolders = [];
        reports = [];
        for (var i = 0; i < response.data.length; i++) {
            if (response.data[i].type == "folder") {
                companyFolders.push(response.data[i]);
                getReportFolders(response.data[i].id + "/files/", companyFolders.length - 1);
            }
        }
        $.when.apply($, companyFolders).done(function() {
            getCompanyFoldersDeferred.resolve();
        });
    }, function(response) {
        log("Cannot get files and folders: " + JSON.stringify(response.error).replace(/,/g, ",\n"));
    });

    return getCompanyFoldersDeferred.promise();
}

function getReportFolders(path, index1) {
    var getReportFoldersDeferred = $.Deferred();
    //var index2 = 0;

    WL.api({
        path: path,
        method: "GET"
    }).then(

    function(response) {
        reportFolders[index1] = [];

        reports[index1] = [];
        for (var i = 0; i < response.data.length; i++) {
            if (response.data[i].type == "folder") {
                reportFolders[index1].push(response.data[i]);
                //index2++;
                getReports(response.data[i].id + "/files/", index1, reportFolders[index1].length - 1);
            }
        }
        $.when.apply($, reportFolders).done(function() {
            getReportFoldersDeferred.resolve();
        });
    }, function(response) {
        log("Cannot get files and folders: " + JSON.stringify(response.error).replace(/,/g, ",\n"));
    });
    return getReportFoldersDeferred.promise();
}

function getReports(path, index1, index2) {
    var getReportsDeferred = $.Deferred();
    //var index3 = 0;

    WL.api({
        path: path,
        method: "GET"
    }).then(

    function(response) {
        reports[index1][index2] = [];

        for (var i = 0; i < response.data.length; i++) {
            if (response.data[i].type == "file") {
                reports[index1][index2].push(response.data[i]);
                //index3++;
            }
        }
        $.when.apply($, reports).done(function() {
            getReportsDeferred.resolve();
        });
    }, function(response) {
        log("Cannot get files and folders: " + JSON.stringify(response.error).replace(/,/g, ",\n"));
    });
    return getReportsDeferred.promise();
}

getCompanyFolders().done(function() {
    showReportsHTML();
});

function showReportsHTML() {
    for (var i = 0; i < companyFolders.length; i++) {
        for (var j = 0; j < reportFolders[i].length; j++) {
            for (var k = 0; k < reports[i][j].length; k++) {
                alert(reports[i][j][k].name);
            }
        }
    }
}

function log(x) {
    alert(x);
}   

these two lines

getCompanyFolders();
showReportsHTML();

shoulde execute functions one after another after getCompanyFolders() function finishes its job. But showReportsHTML() is executet before getCompanyFolders() fills reports 3D array.

How to launch showReportsHTML() function after getCompanyFolders() is fully done?

WL.api() is asynchronous, so execution continues on to the next function.

You can each function return deferred objects:

getCompanyFolders().done(function() {
    showReportsHTML();
});

function getCompanyFolders() {
    var getCompanyDeferred = $.Deferred();

    WL.api({
        path: "/me/skydrive/shared",
        method: "GET"
    }).then(function(response) {
        var deferreds = []
        foreach(item in response) { 
            deferreds.push(getReportFolders());
        }

        $.when.apply($, deferreds).done(function() {
            getCompanyDeferred.resolve();
        });

    });

    return getCompanyDeferred.promise();
}

This is obviously a simplified example. The structure of getReportFolders and getReports would look very similar. Let me know if you need me to take the example further.

Edit in response to your update

A couple things still. First,

getCompanyFolders(); should be:

getCompanyFolders().done(function() {
    showReportsHTML();
});

Second, $.when() accepts deferred or promise objects, which in your case is the return value from your functions.

So in getCompanyFolders , your deferred objects are being returned by the calls to getReportFolders . Those results are what should be pushed into an array and passed to $.when :

function getCompanyFolders() {
    var getCompanyFoldersDeferred = $.Deferred();

    WL.api({
        path: "/me/skydrive/shared",
        method: "GET"
    }).then(

    function(response) {
        companyFolders = [];
        reportFolders = [];
        reports = [];
        var deferreds = []; // <------- new array to hold deferred objects
        for (var i = 0; i < response.data.length; i++) {
            if (response.data[i].type == "folder") {
                companyFolders.push(response.data[i]);
                deferreds.push(getReportFolders(response.data[i].id + "/files/", companyFolders.length - 1)); // <------- hang on to the results from this function
            }
        }
        $.when.apply($, deferreds).done(function() { // <--- wait on all the deferreds to resolve
            getCompanyFoldersDeferred.resolve();
        });
    }, function(response) {
        log("Cannot get files and folders: " + JSON.stringify(response.error).replace(/,/g, ",\n"));
    });

    return getCompanyFoldersDeferred.promise();
}

getReportsFolders needs to be changed similarly.

getReports doesn't need to wait on anything else to resolve. Once we hit the callback, we're done:

function getReports(path, index1, index2) {
    var getReportsDeferred = $.Deferred();
    //var index3 = 0;

    WL.api({
        path: path,
        method: "GET"
    }).then(

    function(response) {
        reports[index1][index2] = [];

        for (var i = 0; i < response.data.length; i++) {
            if (response.data[i].type == "file") {
                reports[index1][index2].push(response.data[i]);
                //index3++;
            }
        }

        getReportsDeferred.resolve();  // <---- all done, nothing else to wait on.

    }, function(response) {
        log("Cannot get files and folders: " + JSON.stringify(response.error).replace(/,/g, ",\n"));
    });
    return getReportsDeferred.promise();
}

It's because getCompanyFolders is calling an asynchronous function. If you want something to happen after this function has finished, you have to provide a callback function:

function getCompanyFolders(callback) {
    companyFolders = [];

    WL.api({
        path: "/me/skydrive/shared",
        method: "GET"
    }).then(

    function(response) {
        reportFolders = [];
        reports = [];
        for (var i = 0; i < response.data.length; i++) {
            if (response.data[i].type == "folder") {
                companyFolders[companyFolders.length] = response.data[i];
                getReportFolders(response.data[i].id + "/files/", companyFolders.length - 1);
            }
        }
        callback();
    }, function(response) {
        log("Cannot get files and folders: " + JSON.stringify(response.error).replace(/,/g, ",\n"));
        callback();
    });
}

Now you can call getCompanyFolders and simply pass showReportsHTML as an argument.

getCompanyFolders(showReportsHTML);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM