JavaScript Wait until all async calls finish

前端 未结 3 1463
礼貌的吻别
礼貌的吻别 2021-01-27 04:46

I need some help with handling async calls in JavaScript. I have a for loop, each loop calls an async HttpRequest, and adds its response to an array. I want the program to wait

相关标签:
3条回答
  • 2021-01-27 05:15

    With promises, you should not use a callback parameter. Call the resolve/reject functions from the promise instead.

    Instead of passing a callback to the call, chain the things you want to do with the result of the promise in a .then handler.

    function httpGet(theUrl) {
        return new Promise(function(resolve, reject) {
            var xmlRequest = new XMLHttpRequest();
            xmlRequest.onreadystatechange = function() {
                if (xmlRequest.readyState == 4) {
                    if (xmlRequest.status == 200) 
                        resolve(xmlRequest.responseText);
        //              ^^^^^^^
                    else
                        reject(new Error(xmlRequest.statusText)); // or something
                }
            }
            xmlRequest.open("GET", theUrl, true);
            xmlRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            xmlRequest.setRequestHeader("Accept", "application/json");
            xmlRequest.send(null);
        });
    }
    $(document).ready(function() {    
        var channels = ["freecodecamp", "storbeck", "terakilobyte", "habathcx", "RobotCaleb", "thomasballinger", "noobs2ninjas", "beohoff"];
        var urls = channels.map((x) => "https://api.twitch.tv/kraken/channels/" + x);
        var promises = urls.map(function(url) {
    //                      ^^^ simpler than forEach+push
            var promise = httpGet(url); // <-- no callback
            return promise.then(JSON.parse);
        });
    
        Promise.all(promises).then(function(data) {
    //                                      ^^^^
            console.log(data);
        });
    })
    
    0 讨论(0)
  • 2021-01-27 05:19

    Since you are using jQuery you can use the Deferred Object to chain promises.

    Collect all the promises and use $.when with spread operator to wait for all promises to resolve. You can use then to run a function after all ajax requests are resolved.

    ES5 Example

    $(document).ready(function () {
    
        var channels = ["freecodecamp", "storbeck", "terakilobyte", "habathcx", "RobotCaleb", "thomasballinger", "noobs2ninjas", "beohoff"];
        var urls = channels.map(function (x) {
            return "https://api.twitch.tv/kraken/channels/" + x;
        });
        var data = [];
        var promises = urls.map(function (url) {
            return $.get(url).then(function (response) {
                data.push(response);
            });
        });
    
        $.when.apply($, promises).then(function () {
            console.log('done', data);
        });
    });
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

    ES6 Example

    $(document).ready(function() {    
        var channels = ["freecodecamp", "storbeck", "terakilobyte", "habathcx","RobotCaleb","thomasballinger","noobs2ninjas","beohoff"];
        var urls = channels.map((x) => "https://api.twitch.tv/kraken/channels/" + x);
        var data = [];
        var promises = urls.map((url) => $.get(url).then((response) => {
            data.push(response);
        }));
    
        $.when(...promises).then(function() {
            console.log('done', data);
        });
    });
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

    0 讨论(0)
  • 2021-01-27 05:24

    Can't it be done by just keeping the count of ajax requests as a variable:

    var urls_count, data_count = 0;
    function httpGet(theUrl, callback, onComplete) {
        var xmlRequest = new XMLHttpRequest();
        xmlRequest.onreadystatechange = function() {
            if (xmlRequest.readyState == 4 && xmlRequest.status == 200) {
                callback(xmlRequest.responseText);
            }
            if(xmlRequest.readyState == 4){
                data_count += 1
                if(urls_count == data_count){
                    //this is called when all ajax calls complete
                    onComplete();
                }
            }
        }
        xmlRequest.open("GET", theUrl, true);
        xmlRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        xmlRequest.setRequestHeader("Accept", "application/json");
        xmlRequest.send(null);
    }
    $(document).ready(function() {    
        var channels = ["freecodecamp", "storbeck", "terakilobyte", "habathcx","RobotCaleb","thomasballinger","noobs2ninjas","beohoff"];
        var urls = channels.map((x) => "https://api.twitch.tv/kraken/channels/" + x);
        var data = [];
        urls_count = urls.length;
        var onComplete = function(){
            //your code after all ajax completes.
        }
        (function(urls, data) {
            urls.forEach(function(url) {  
                function(resolve, reject) {
                    httpGet(url, function(response) {
                        data.push(JSON.parse(response));
                    }, onComplete)
                };
            })
        })(urls, data);
    })
    
    0 讨论(0)
提交回复
热议问题