javascript - 在 JavaScript 中异步执行循环中的函数 - 在哪里放置 defer.resolve?

标签 javascript node.js asynchronous promise sails.js

我有 java/python 背景,对 javascript 很陌生。我需要创建一个产品列表,其中包含其子项的描述,并包含在 jsonarray 中。

父列表:

[{ children: [ 100714813, 100712694 ],
  sp: '89.10',
  weight: '1 ltr',
  pack_type: 'Carton',
  brand: 'Real',
  p_desc: 'Fruit Power Juice - Orange' }]

现在,对于每个父级,我需要通过连接到数据库再次迭代地获取子级详细信息,最后将结果合并到单个 jsonarray 中。但是当我执行下面的代码时,控件不会等待获取子级数据(这很有意义,因为它被异步调用!),我得到的结果是一个 jsonarray,其中仅包含没有子级的父级的数据。

exports.productDetailsQuery = function(options) {

    var AEROSPIKE_NAMESPACE = '';  
    var AEROSPIKE_SET = 'products';
    var PD_KEY_VERSION_NUMBER = '1';

    var defer = sails.Q.defer();

    var results = options.results;
    var parent_list = [];
    var finalData = [];

    var productKeys = results.map(
        function(x){
            return {
                ns: AEROSPIKE_NAMESPACE,
                set: AEROSPIKE_SET,
                key: "pd.v" + PD_KEY_VERSION_NUMBER + '.' + 'c' + options.city_id + '.' + x.sku.toString()
            }
        }
    );

    var status = require('aerospike').status;
    var breakException = {};

    // Read the batch of products.
    sails.aerospike.batchGet(productKeys, function (err, results) {
        if (err.code === status.AEROSPIKE_OK) {
            for (var i = 0; i < results.length; i++) {
                switch (results[i].status) {
                    case status.AEROSPIKE_OK:
                        parent_list.push(results[i].record);
                        break;
                    case status.AEROSPIKE_ERR_RECORD_NOT_FOUND:
                        console.log("NOT_FOUND - ", results[i].keys);
                        break;
                    default:
                        console.log("ERR - %d - ", results[i].status, results[i].keys);
                }
            }
            parent_list.forEach(function(parent){
                var children = parent['children'];
                console.log(children)
                if(children){
                    var childKeys = children.map(function(child){
                        return {
                            ns: AEROSPIKE_NAMESPACE,
                            set: AEROSPIKE_SET,
                            key: "pd.v" + PD_KEY_VERSION_NUMBER + '.' + 'c' + options.city_id + '.' + child.toString()
                        }
                    });
                    sails.aerospike.batchGet(childKeys, function(err, childData){
                        if(err.code === status.AEROSPIKE_OK){
                            console.log('this called')
                            var entry = {};
                            entry['primary_prod'] = parent;
                            entry['variants'] = childData;
                            finalData.push(entry);
                        }
                    });
                }
                else{
                    var entry = {};
                    entry['primary_prod'] = parent;
                    finalData.push(entry);
                }
            });
            defer.resolve(finalData);
        } else {
            defer.reject(err);
        }
    });

    return defer.promise;
}

我需要 FinalData 如下:

[{"primary_prod":{ children: [ 100714813, 100712694 ],
  sp: '89.10',
  weight: '1 ltr',
  pack_type: 'Carton',
  brand: 'Real',
  p_desc: 'Fruit Power Juice - Orange' },
"variants":[{child_data},{child_data}]}, ...........]

非常感谢有关如何使其工作的任何帮助。是否有特定的模式来处理此类情况?

谢谢!

最佳答案

您所写的内容是正确的,但只有外部 batchGet() 被 promise 。因为没有尝试 promise 内部 batchGet(),所以它不会对最终返回的 promise 做出贡献。

你的整体模式可能是这样的......

exports.productDetailsQuery = function(options) {
    return sails.aerospike.batchGetAsync(...).then(results) {
        var promises = results.filter(function(res) {
            // Filter out any results that are not `AEROSPIKE_OK`
            ...
        }).map(function(parent) {
            // Map the filtered results to an array of promises
            return sails.aerospike.batchGetAsync(...).then(function(childData) {
                ...
            });
        });
        // Aggregate the array of promises into a single promise that will resolve when all the individual promises resolve, or will reject if any one of the individual promises rejects.
        return sails.Q.all(promises);
    });
}

...其中 batchGetAsync()batchGet() 的 promise 版本。

完全充实的代码会更长,但通过首先定义几个实用函数,可以保持相当简洁和可读。你最终可能会得到这样的结果:

// utility function for making a "key" object
function makeKey(obj) {
    return {
        ns: '', //AEROSPIKE_NAMESPACE
        set: 'products', //AEROSPIKE_SET
        key: 'pd.v1.c' + options.city_id + '.' + obj.toString()
    }
}

// promisified version of batchGet()
function batchGetAsync(obj) {
    var defer = sails.Q.defer();
    batchGet(obj, function(err, results) {
        if(err.code === status.AEROSPIKE_OK) {
            defer.resolve(results);
        } else {
            defer.reject(err);
        }
    });
    return defer.promise; 
}

var status = require('aerospike').status;

// Main routine
exports.productDetailsQuery = function(options) {
    return batchGetAsync(options.results.map(makeKey)).then(results) {
        var promises = results.filter(function(res) {
            if (res.status === status.AEROSPIKE_OK) {
                return true;
            } else if(status.AEROSPIKE_ERR_RECORD_NOT_FOUND) {
                console.log("NOT_FOUND - ", res.keys);
            } else {
                console.log("ERR - %d - ", res.status, res.keys);
            }
            return false;
        }).map(function(parent) {
            var entry = { 'primary_prod': parent },
                children = parent['children'];
            if(children) {
                return batchGetAsync(children.map(makeKey)).then(function(childData) {
                    entry.variants = childData;
                    return entry;
                });
            } else {
                return entry;
            }
        });
        return sails.Q.all(promises);
    });
}

关于javascript - 在 JavaScript 中异步执行循环中的函数 - 在哪里放置 defer.resolve?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32394603/

相关文章:

javascript - Phonegap db.transaction 回调多次触发

javascript - AngularJS:一键隐藏表单而不显示错误消息

javascript - Uncaught ReferenceError : addFriend is not defined

node.js - 遍历整个 mongo 数据库的方法太大而无法加载?

javascript - 如何停止点击事件 javascript 上的异步函数?

vb.net - 使用 Async-await 时 UI 卡住

javascript - Polymer - 设置数组不更新 DOM

javascript - Windows 7 中的 HTML5 Canvas drawImage 问题,但仅在 Firefox 中

javascript - 如何在 Node.js 和 JXcore 之间进行选择?

javascript - Jade Mixin - 对象操作