一尘不染

Node.JS如何在当前范围之外设置变量

node.js

我有一些我无法理解的代码,我试图使用回调返回对象数组,我有一个函数返回值,然后将其压入数组,但是我无法在函数外部访问它,我在这里做一些愚蠢的事情,但无法分辨(我对Node.JS非常陌生)

                    for (var index in res.response.result) {
                    var marketArray = [];
                    (function () {
                        var market = res.response.result[index];
                        createOrUpdateMarket(market, eventObj , function (err, marketObj) {
                            marketArray.push(marketObj)
                            console.log('The Array is %s',marketArray.length) //Returns The Array is 1.2.3..etc
                        });
                        console.log('The Array is %s',marketArray.length) // Returns The Array is 0

                    })();

                }

阅读 213

收藏
2020-07-07

共1个答案

一尘不染

您在这里遇到了多个问题。核心问题是要了解异步响应如何工作以及何时执行哪些代码。但是,除此之外,您还必须学习如何在循环中管理多个异步响应,以及如何知道何时完成所有响应以及如何按顺序获取结果以及最好在node.js中使用哪些工具来去做。

您的核心问题是时间问题。该createOrUpdateMarket()功能可能是异步的。这意味着它在调用该函数时开始其操作,然后在将来的某个时间调用其回调。同时,其余代码将继续运行。因此,您试图在调用回调之前访问数组。

因为您无法确切知道何时会调用该回调,所以唯一可以可靠使用回调数据的位置是在回调内部或在回调内部被调用的位置。

要知道createOrUpdateMarket()所有这些操作何时全部完成,您将必须编写代码,尤其是要知道所有这些操作何时完成,并且您不能依赖简单的for循环。现代的方法是使用promise,promise提供工具来帮助您管理一个或多个异步操作的时序。

此外,如果您想累积forin中的循环结果marketArray,则必须在for循环之前而不是for循环内部声明并初始化它。以下是几种解决方案:

手动编码解决方案

var len = res.response.result.length;
var marketArray = new Array(len), cntr = 0;
for (var index = 0, index < len; index++) {
    (function(i) {
        createOrUpdateMarket(res.response.result[i], eventObj , function (err, marketObj) {
            ++cntr;
            if (err) {
                // need error handling here
            }
            marketArray[i] = marketObj;
            // if last response has just finished
            if (cntr === len) {
                // here the marketArray is fully populated and all responses are done
                // put your code to process the marketArray here
            }
        });
    })(index);
}

内置到Node.js中的标准承诺

// make a version of createOrUpdateMarket that returns a promise
function createOrUpdateMarketAsync(a, b) {
    return new Promise(function(resolve, reject) {
        createOrUpdateMarket(a, b, function(err, marketObj) {
            if (err) {
                reject(err);
                return;
            }
            resolve(marketObj);
        });
    });
}

var promises = [];
for (var i = 0; i < res.response.result.length; i++) {
    promises.push(createorUpdateMarketAsync(res.response.result[i], eventObj));
}
Promise.all(promises).then(function(marketArray) {
    // all results done here, results in marketArray
}, function(err) {
    // an error occurred
});

Bluebird Promise库增强了承诺

蓝鸟的Promise库提供Promise.map()了将迭代您的数据数组并生成一系列异步获取的结果的功能。

// make a version of createOrUpdateMarket that returns a promise
var Promise = require('bluebird');
var createOrUpdateMarketAsync = Promise.promisify(createOrUpdateMarket);

// iterate the res.response.result array and run an operation on each item
Promise.map(res.response.result, function(item) {
    return createOrUpdateMarketAsync(item, eventObj);
}).then(function(marketArray) {
    // all results done here, results in marketArray
}, function(err) {
    // an error occurred
});

异步库

您还可以使用异步库来帮助管理多个异步操作。在这种情况下,您可以使用async.map()which将创建结果数组。

var async = require('async');
async.map(res.response.result, function(item, done) {
    createOrUpdateMarker(item, eventObj, function(err, marketObj) {
        if (err) {
            done(err);
        } else {
            done(marketObj);
        }
    });
}, function(err, results) {
    if (err) {
        // an error occurred
    } else {
        // results array contains all the async results
    }
});
2020-07-07