javascript - 在 for 循环内同步 promise ?

标签 javascript promise

我被 angularjs/javascript 的异步执行所困扰。请帮忙

注释

用于示例目的的虚拟 API。

那些虚拟 API 实际上是一个实时的 AnugularJS 服务。

我使用 XmlHttpRequest 进行演示,因此无需争论第三个参数是 false 还是 true。

问题

在for循环内,调用calculateFormulaValue函数并根据参数,它将调用一些API并获取 promise 对象中的值。但是 for 循环在返回 Promise 对象之前就完成了,并且我无法将最终对象保存在 rowCollection 中。

我们如何重构下面的代码以获得期望的结果?

此处代码 -> https://jsbin.com/xocisivuro/edit?js,console

代码

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 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}"

预期输出

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

任何有助于实现预期输出的帮助都会很好。提前致谢。

最佳答案

您可以通过在此处放置 return 关键字来返回在 calculateFormulaValue 中创建的 promise :

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

在拥有此构造的所有地方执行此操作,以确保函数始终返回 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);
});

现在您可以使用 Promise.all 等待所有 Promise 完成:

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

注意:您应该进一步改进代码以避免使用全局变量,例如结果对象currentFormulaValues

关于javascript - 在 for 循环内同步 promise ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41323535/

相关文章:

javascript - 如何延迟选择选项生成

javascript - Node.js Express-Session + Redis 单实例问题

Angular 4 typescript 从 promise 中获取数组

javascript - 如何在执行函数之前加载一些图像

javascript - UI Router 更改 URL 但不更改页面

javascript - 使用 appendChild 将图像添加到元素会产生错误

javascript - 换行后隐藏元素

javascript - Angular - 解析器和组件不共享注入(inject)的服务?

validation - 自定义异步验证在返回 promise 时不起作用

javascript - 清理 React Hooks 中未安装组件的内存泄漏