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

时间:2015-09-26 17:02:29

标签: javascript 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

                    })();

                }

1 个答案:

答案 0 :(得分:3)

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

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

因为您无法准确知道何时调用该回调,所以您可以可靠地使用回调数据的唯一地方是回调内部或者在回调中调用的内容。

您可以在此处详细了解异步/回调问题:Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference

要知道这些createOrUpdateMarket()操作的全部系列何时完成,您必须特别编写代码以了解所有这些操作何时完成,并且您不能依赖简单的for循环。现代化的方法是使用promises,它提供了帮助您管理一个或多个异步操作的时间的工具。

此外,如果您想累积formarketArray循环的结果,则必须在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库增强了承诺

bluebird 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()来创建一系列结果。

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