【问题标题】:Pushing to an array inside of a loop inside of a callback function推送到回调函数内循环内的数组
【发布时间】:2015-02-12 12:06:18
【问题描述】:

我有一个需要在回调内部运行的循环,不幸的是,访问回调外部的数组会给我留下一个空白数组。我知道为什么会发生这种情况,但我想知道解决这个问题的最佳解决方案。

Gallery.prototype.getGallery = function(cb) {
self = this;
var cos = new pb.CustomObjectService();
var ms = new pb.MediaService();

var s = [];

cos.loadTypeByName('Gallery Image', function(err, gallery){

    cos.findByType(gallery._id.toString(), function(err, rpy){

        for(var i = 0; i < rpy.length; i++){
            ms.loadById(rpy[i].Image, function(e,r){
                s.push(r.location);
                console.log(r.location); /* <-- logs expected data */
            });     
       }
       console.log(s[0]); /* <-- this is undefined  */
    });
});
};

【问题讨论】:

  • 我不是反对者,但这个问题已经在 SO 上被问过并回答了几十次。为什么你会想象在异步调用完成之前数组会被填充?回调是异步执行的——这意味着“将来的某个时候”。除非你有一台时间机器,否则你无法访问在未来某个时间才会设置的变量。
  • 感谢 torazaburo,正如我所说,我知道为什么......问题是解决这个问题的最优雅的方法。

标签: node.js


【解决方案1】:

将您的for 循环替换为对async.* 的调用;在这种情况下,async.map 似乎是正确的。将回调传递给async.map;当对ms.loadById 的所有单独调用都完成时,它将被调用,并带有结果数组。

async.map(
    rpy, 
    function(elt, callback) {
        ms.loadById(elt.Image, callback);
    },
    function(err, data) {
        // comes here after all individual async calls have completed
        // check errors; array of results is in data
    }
);

如果您想进入 Promise 世界,请将对 ms.loadById 的调用封装在 Promise 中。这是一个自己滚动的版本,但通常称为promisify 的各种版本也有。

function loadByIdPromise(elt) {
    return new Promise(function(resolve, reject) {
        ms.loadById(elt.image, function(err, data) {
            if (err) return reject(err);
            resolve(data);
        });
    });
}

然后对生成的承诺执行Promise.all

Promise.all(rpy.map(loadByIdPromise))
    .then(function(data) {
        // comes here when all individual async calls complete successfully
        // data is your array of results
    });

使用 promises 样式,您的整个代码将如下所示:

loadTypeByNamePromise('Gallery Image') .
    then(function(gallery) { return findByTypePromise(gallery._id.toString(); }) . 
    then(function(rpy)     { return Promise.all(rpy.map(loadByIdPromise)); }) .
    then(function(results) { /* do something with [results] */ });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-14
    • 2023-03-26
    • 2013-07-30
    • 2021-06-14
    • 2021-05-28
    • 2019-06-20
    • 1970-01-01
    • 2023-03-10
    相关资源
    最近更新 更多