在promise()中声明循环

时间:2016-01-28 16:28:35

标签: javascript promise rxjs

我有一个奇怪的情况,我想在收到Rx Promise的结果并做一些检查后打破for循环。我所拥有的是以下内容:

<!-- assume the border-bottom is only applied to an active=clicked navigation tab -->
<h1 style="border-bottom: 3px solid green;">Tab1</h1>
<h1>Tab2</h1>

其中function getDrift(groups) { var drift = {}; groups.forEach(function(group) { if(group.type === 'something') { for(var i = 0; i < group.entries.length; i++) { fetchEntry(group.entries[i].id) .then(function(entry) { if(entry.type === 'someType'){ drift[entry._id] = getCoordinates(entry); // break; } }); } } }); return drift; } 基于id返回mongodb文档的Promise。如果满足fetchEntry检查,我想打破当前if的循环并继续下一组。

这可能吗?

由于

编辑:根据要求,群组对象如下所示:

group.entries

解决方案:我最终使用@MikeC的建议进行递归和回调以返回所需的值。谢谢大家!

4 个答案:

答案 0 :(得分:6)

这是不可能的,因为Promises是异步的,这意味着then won't execute until all other synchronous code completes.

如果您不想根据某些条件处理所有这些条件,我建议您创建一个函数,如果要继续,可以调用它。

(function process(index) {
  if (index >= group.entries.length) {
    return;
  }
  fetchEntry(group.entries[index])
    .then(function(entry) {
      if(entry.type === 'someType'){
        drift[entry._id] = getCoordinates(entry);
        // don't call the function again
      } else {
        process(index + 1);
      }
    });
})(0);

答案 1 :(得分:3)

传递给then()的函数不在for循环中调用。在for循环结束后调用(long)。这是异步编程模型的本质。

您需要重新组织代码,以便不使用for循环。相反,您需要在回调中启动下一次抓取,或者不要在适当时启动它。

PS。由于同样的原因,您无法返回由回调填充的对象:您的函数将返回空对象/调用回调之前

编辑:演示,但代码未经测试:

function getDrift(groups) {
    var promise = ...;

    var drift = {};
    groups.forEach(function(group) {
        if(group.type === 'something') {
            var i = 0;

            var processEntry = (function(entry) {
                     if(entry.type === 'someType'){
                         drift[entry._id] = getCoordinates(entry);

                         // We are finished, so complete our promise with
                         // the collected data
                         promise.success(drift);
                         return;
                     }

                     // increment our position in the array
                     i += 1;

                     // check to see if we are at the end of the array
                     if (i >= group.entries.length)
                        { return; }

                     // now fetch the next entry from the array
                    fetchEntry(group.entries[i].id)
                            .then(processEntry);
                 });

            // fetch the first entry
            fetchEntry(group.entries[i].id)
                 .then(processEntry);

            } // end if

    }); // end forEach()

    return promise;
}

答案 2 :(得分:0)

  

如果满足if检查,我想打破当前的循环   group.entries并继续下一组。

如果正确解释问题,请尝试使用Promise.all()Array.prototype.map()

&#13;
&#13;
function getDrift(groups) {
  var drift = {};
  var m = 0;
  return Promise.all(groups.map(function(p) {
    // if `p` contains `5` return `null`
    // else multiply item within `p` by `10`
    return p.indexOf(5) === -1 ? p.map(function(k) {
      drift[m] = k * 10;
      ++m
    }) : null
  })).then(function(n) {
    return drift
  }, function(err) {
    console.log(err)
  })

}
// array containing `5` will not be processed
var res = getDrift([[1,2,3], [4,5,6], [7,8,9]])
.then(function(data) {
  console.log(data)
})
&#13;
&#13;
&#13;

在问题

上将模式应用于js
function getDrift(groups) {
  var drift = {};
  return Promise.all(groups.map(function(group) {
    return group.type === "something" 
    ? Promise.all(group.entries.map(function(g, index) {
      return fetchEntry(g.id).then(function(entry) {
         if (entry.type === "someType") {
            drift[entry._id] = getCoordinates(entry);
            return Promise.reject(entry.type);
         }
      })
    })) 
    : null
  })).then(function() {
    return drift
  }, function(err) {
    console.log(err)
  })

}
// array containing `5` will not be processed
var res = getDrift(groups)
.then(function(data) {
  console.log(data)
}, function(err) {
  console.log(err)
})

答案 3 :(得分:0)

这可能是没有递归,但不是特别简单。

您可以使用以下组合:

  • forEach()替换为Array#map()以将groups映射到承诺数组,
  • 将原始for循环替换为Array#reduce()以构建.then()链,这是&#34;易碎的&#34;通过发送它的错误路径。

到目前为止最简单的事情是根据问题中的代码坚持使用drift作为外部变量。通过承诺链交付数据也是可能的,但代码会更复杂。

function getDrift(groups) {
    var drift = {};
    // Map groups to an array of promises.
    var promises = groups.map(function(group) {
        if(group.type === 'something') {
            // Here, replace the original `for` loop with `group.entries.reduce()` to build a .then() chain.
            return group.entries.reduce(function(p, e) {
                return p.then(function() {
                    return fetchEntry(e.id).then(function(entry) {
                        if(entry.type === 'someType') {
                            drift[entry._id] = getCoordinates(entry); // Yay!
                            throw false; // Throw almost anything here to skip the rest of the .then() chain.
                        } else {
                            return true; // Return almost anything here to carry on down the chain.
                        }
                    });
                });
            }, Promise.resolve()) // Resolved starter promise for the reduction.
            .catch(function() { // If there was a match, we end up on the error path, and need to convert to success.
                return true; // Return almost anything here.
            });
        } else {
            return true; // Return almost anything here to make a positive entry on the `promises` array.
        }
    });
    return Promise.all(promises) // Aggregate the promises.
    .then(function() {
        return drift; // and deliver the populated `drift` to the calling function
    });
}

getDrift()返回一个承诺时,drift仅在.then()回调中可供调用者使用:

getDrift(groups).then(function(drift) {
    //do something with drift
});