简体   繁体   English

在for循环中同步诺言?

[英]synchronize promises inside for loop?

I'm stuck with this asynchronous execution of angularjs/javascript. 我对angularjs / javascript的异步执行感到困惑。 Please help 请帮忙

NOTES 笔记

Dummy API used for sample purpose. 虚拟API用于示例目的。

Those Dummy API are really an AnugularJS service in real time. 那些Dummy API实际上是实时的AnugularJS服务。

I used XmlHttpRequest for demo purpose, so no need to debate on third argument being false or true. 我将XmlHttpRequest用于演示目的,因此无需争论第三个参数是false还是true。

PROBLEM 问题

Inside for loop, calculateFormulaValue function is called and based on argument, it will call some API and get value in promised object. 在for循环中,调用了calculateFormulaValue函数,并基于参数,它将调用一些API并在承诺的对象中获取值。 But for loop is getting finished before promise object gets returned and I'm not able to save the final object in rowCollection . 但是for循环在返回promise对象之前就已经完成了,而我无法将最终对象保存在rowCollection中

How we can refactor below code to get desired result ? 我们如何重构下面的代码以获得所需的结果?

Code here -> https://jsbin.com/xocisivuro/edit?js,console 在这里编码-> https://jsbin.com/xocisivuro/edit?js,控制台

CODE

var rowCollection = [];
var headerCollection = ["Formula 1", "Formula 2", "Formula 3", "Formula 4", "Formula 5", "Formula 6", "Formula 7"];
var currentFormulaValues = {};
//var finalCollection = 
function generate(){

    for(var i=0;i<headerCollection.length;i++){

        calculateFormulaValue(i,headerCollection[i]);
        console.log("current index" +i + " -->" +headerCollection[i]);


    }
}

function calculateFormulaValue(j,currentFormula){

    //Some common code which need to run ..

    if(currentFormula == "Formula 1"){
        var promise = new Promise(function(resolve, reject) {
        var request = new XMLHttpRequest();

        request.open('GET', 'https://api.icndb.com/jokes/random');
        request.onload = function() {
          if (request.status == 200) {
            resolve(request.response);
          } else {

            reject(Error(request.statusText));
          }
        };

        request.onerror = function() {reject(Error('Error fetching data.')); 
        };

        request.send();
      });

      promise.then(function(data) {

        currentFormulaValues[currentFormula] = JSON.parse(data).value.id;
        //rowCollection[j] = JSON.parse(data).value.id;

        console.log("j - " + j +" ->" + (JSON.stringify(currentFormulaValues)));
      }, function(error) {
        console.log('Promise rejected.');
      });
    }

    else if(currentFormula == "Formula 2"){
        var promise = new Promise(function(resolve, reject) {
        var request = new XMLHttpRequest();

        request.open('GET', 'https://api.icndb.com/jokes/random');
        request.onload = function() {
          if (request.status == 200) {
            resolve(request.response);
          } else {

            reject(Error(request.statusText));
          }
        };

        request.onerror = function() {reject(Error('Error fetching data.')); 
        };

        request.send();
      });

      promise.then(function(data) {
        currentFormulaValues[currentFormula] = JSON.parse(data).value.id;
        //rowCollection[j] = JSON.parse(data).value.id;
        console.log("j - " + j +" ->" + (JSON.stringify(currentFormulaValues)));

      }, function(error) {
        console.log('Promise rejected.');
      });
    }

    // for all other formulas

    else{
        var promise = new Promise(function(resolve, reject) {
        var request = new XMLHttpRequest();

        request.open('GET', 'https://api.icndb.com/jokes/random');
        request.onload = function() {
          if (request.status == 200) {
            resolve(request.response);
          } else {

            reject(Error(request.statusText));
          }
        };

        request.onerror = function() {reject(Error('Error fetching data.')); 
        };

        request.send();
      });

      promise.then(function(data) {

        currentFormulaValues[currentFormula] = JSON.parse(data).value.id;
        //rowCollection[j] = JSON.parse(data).value.id;
        console.log("j - " + j +" ->" + (JSON.stringify(currentFormulaValues)));

      }, function(error) {
        console.log('Promise rejected.');
      });

    }

     if(j == headerCollection.length-1){
        console.log("SAVE FINAL")
        rowCollection.push(currentFormulaValues);
        console.log(JSON.stringify(currentFormulaValues))
      } 
}

CURRENT OUTPUT 电流输出

"current index0 -->Formula 1"
"current index1 -->Formula 2"
"current index2 -->Formula 3"
"current index3 -->Formula 4"
"current index4 -->Formula 5"
"current index5 -->Formula 6"
"SAVE FINAL"
"{}"
"current index6 -->Formula 7"
"j - 0 ->{\"Formula 1\":98}"
"j - 1 ->{\"Formula 1\":98,\"Formula 2\":175}"
"j - 2 ->{\"Formula 1\":98,\"Formula 2\":175,\"Formula 3\":523}"
"j - 3 ->{\"Formula 1\":98,\"Formula 2\":175,\"Formula 3\":523,\"Formula 4\":399}"
"j - 4 ->{\"Formula 1\":98,\"Formula 2\":175,\"Formula 3\":523,\"Formula 4\":399,\"Formula 5\":119}"
"j - 5 ->{\"Formula 1\":98,\"Formula 2\":175,\"Formula 3\":523,\"Formula 4\":399,\"Formula 5\":119,\"Formula 6\":261}"
"j - 6 ->{\"Formula 1\":98,\"Formula 2\":175,\"Formula 3\":523,\"Formula 4\":399,\"Formula 5\":119,\"Formula 6\":261,\"Formula 7\":164}"

EXPECTED OUTPUT 预期的输出

"current index0 -->Formula 1"
"j - 0 ->{\"Formula 1\":98}"

"current index1 -->Formula 2"
"j - 1 ->{\"Formula 1\":98,\"Formula 2\":175}"

"current index2 -->Formula 3"
"j - 2 ->{\"Formula 1\":98,\"Formula 2\":175,\"Formula 3\":523}"

"current index3 -->Formula 4"
"j - 3 ->{\"Formula 1\":98,\"Formula 2\":175,\"Formula 3\":523,\"Formula 4\":399}"

"current index4 -->Formula 5"
"j - 4 ->{\"Formula 1\":98,\"Formula 2\":175,\"Formula 3\":523,\"Formula 4\":399,\"Formula 5\":119}"

"current index5 -->Formula 6"
"j - 5 ->{\"Formula 1\":98,\"Formula 2\":175,\"Formula 3\":523,\"Formula 4\":399,\"Formula 5\":119,\"Formula 6\":261}"

"current index6 -->Formula 7"
"j - 6 ->{\"Formula 1\":98,\"Formula 2\":175,\"Formula 3\":523,\"Formula 4\":399,\"Formula 5\":119,\"Formula 6\":261,\"Formula 7\":164}"


//if j == headerCollection.length-1, then..

"SAVE FINAL"  // then do ... rowCollection.push(currentFormulaValues);

Any help in achieving expecting output would be good. 对实现预期输出的任何帮助都是好的。 Thanks in advance. 提前致谢。

You could return the promise that you create in calculateFormulaValue , by putting the return keyword here: 您可以通过在此处放置return关键字来return您在calculateFormulaValue中创建的promise:

return promise.then(function(data) { // ... etc

Do this at all places where you have this construct to make sure the function always returns the promise (or even better: try to reuse code that common to each formula -- you have a lot of code duplication there). 在具有此构造的所有位置执行此操作,以确保函数始终返回promise(甚至更好:尝试重用每个公式通用的代码-那里有很多重复的代码)。

Then your main loop could build a new array where each element is the returned promise: 然后,您的主循环可以构建一个新数组,其中每个元素都是返回的promise:

var promises = headerCollection.map(function (collection, i) {
    console.log("current index" +i);
    // return(!) the promise you get from each call. This will become 
    // an element in a new array, returned by *map*.
    return calculateFormulaValue(i, collection);
});

And now you can wait for all promises to finish with Promise.all : 现在您可以等待Promise.all完成所有承诺:

Promise.all(promises).then(function () {
    // now your object is available.
});

NB: you should further improve your code to avoid the use of global variables, such as the result object currentFormulaValues . 注意:您应该进一步改进代码,以避免使用全局变量,例如结果对象currentFormulaValues

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

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