简体   繁体   English

JavaScript 等待所有异步调用完成

[英]JavaScript Wait until all async calls finish

I need some help with handling async calls in JavaScript.我需要一些帮助来处理 JavaScript 中的异步调用。 I have a for loop, each loop calls an async HttpRequest, and adds its response to an array.我有一个 for 循环,每个循环调用一个异步 HttpRequest,并将其响应添加到一个数组中。 I want the program to wait until all the async calls are finished before proceeding without jQuery (which is only used for DOM manipulation).我希望程序在没有 jQuery(仅用于 DOM 操作)的情况下继续之前等待所有异步调用完成。 I've searched quite bit for solutions but none really worked without heavily changing my code or relying on jQuery.我已经搜索了相当多的解决方案,但没有一个真正有效的没有大量改变我的代码或依赖 jQuery。

function httpGet(theUrl, callback) {
    var xmlRequest = new XMLHttpRequest();
    xmlRequest.onreadystatechange = function() {
        if (xmlRequest.readyState == 4 && xmlRequest.status == 200) {
            callback(xmlRequest.responseText);
        }
    }
    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 = [];
    (function(urls, data) {
        urls.forEach(function(url) {  
            function(resolve, reject) {
                httpGet(url, function(response) {
                    data.push(JSON.parse(response));
                })
            };
        })
    })(urls, data);

    // Continue after all async calls are finished
})

UPDATED : Edited with Promise, but still not working, maybe I did something wrong.更新:使用 Promise 进行编辑,但仍然无法正常工作,也许我做错了什么。

function httpGet(theUrl, callback) {
    return new Promise(function(resolve, reject) {
        var xmlRequest = new XMLHttpRequest();
        xmlRequest.onreadystatechange = function() {
            if (xmlRequest.readyState == 4 && xmlRequest.status == 200) {
                callback(xmlRequest.responseText);
            }
        }
        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 = [];
    var promises = [];
    (function(urls, data) {
        urls.forEach(function(url) {  
            var promise = httpGet(url, function(response) {
                data.push(JSON.parse(response));
            });
            promises.push(promise);
        })

        Promise.all(promises).then(function() {
            console.log(data);
        })
    })(urls, data);
})

With promises, you should not use a callback parameter.对于 Promise,您不应该使用callback参数。 Call the resolve / reject functions from the promise instead.改为从reject调用resolve / reject函数。

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.不要将回调传递给调用,而是将您想要做的事情与.then处理程序中的承诺结果链接起来。

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

Since you are using jQuery you can use the Deferred Object to chain promises.由于您使用的是 jQuery,您可以使用延迟对象来链接承诺。

Collect all the promises and use $.when with spread operator to wait for all promises to resolve.收集所有承诺并使用$.when和 spread 运算符来等待所有承诺解决。 You can use then to run a function after all ajax requests are resolved.您可以使用then在解决所有 ajax 请求后运行一个函数。

ES5 Example ES5 示例

 $(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 ES6 示例

 $(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>

Can't it be done by just keeping the count of ajax requests as a variable:难道不能通过将 ajax 请求的计数作为一个变量来完成:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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