由于异步/同步问题导致NodeJS循环问题

时间:2017-09-15 16:18:34

标签: javascript node.js api asynchronous promise

我正在移植旧的ruby脚本以使用javascript将该函数设置为cron实例,因此它将按计划运行。该函数查询我们的mysql数据库并检索我们产品的库存信息,然后将请求发送给贸易伙伴api以更新我们网站上的库存。

由于节点是同步的,我遇到了问题。我们需要将请求分块为每个请求1000个项目,我们发送10k产品。问题是每个请求每次只发送最后1000个项目。 while循环中的for循环在完成json请求体的制作之前向前移动。我尝试在while循环中创建anon setTimeout函数来尝试处理它,以及创建一个带有请求函数的对象和要传递的变量,并将其填充到一个数组中,一旦while循环完成迭代,但我得到了同样的结果。不知道什么是处理它的最佳方式,以便每个请求获得正确的批次项目。我还需要在1000个项目的每个请求之间等待3分钟才能达到请求上限。

  query.on('end',()=>{
                   connection.release();
                   writeArray = itemArray.slice(0),
                   alteredArray = [];
                   var csv = json2csv({data: writeArray,fields:fields}),
                   timestamp = new Date(Date.now());
                   timestamp = timestamp.getFullYear() + '-' +(timestamp.getMonth() + 1) + '-' + timestamp.getDate()+ ' '+timestamp.getHours() +':'+timestamp.getMinutes()+':'+timestamp.getSeconds();
                   let fpath = './public/assets/archives/opalEdiInventory-'+timestamp+'.csv';

                   while(itemArray.length > 0){
                        alteredArray = itemArray.splice(0,999);
                        for(let i = 0; i < alteredArray.length; i++){
                            jsonObjectArray.push({
                                sku: alteredArray[i]['sku'],
                                quantity: alteredArray[i]["quantity"],
                                overstockquantity: alteredArray[i]["osInv"],
                                warehouse: warehouse,
                                isdiscontinued: alteredArray[i]["disc"],
                                backorderdate: alteredArray[i]["etd"],
                                backorderavailability: alteredArray[i]["boq"]
                            });
                        }

                        var jsonObject = {
                            login: user,
                            password: password,
                            items: jsonObjectArray
                        };

                        postOptions.url = endpoint;
                        postOptions.body = JSON.stringify(jsonObject);
                        funcArray.push({func:function(postOptions){request(postOptions,(err,res,body)=>{if(err){console.error(err);throw err;}console.log(body);})},vars:postOptions});
                        jsonObjectArray.length = 0;
                    }
                    var mili = 180000;
                    for(let i = 0;i < funcArray.length; i++){
                        setTimeout(()=>{
                            var d = JSON.parse(funcArray[i]['vars'].body);
                            console.log(d);
                            console.log('request '+ i);
                            //funcArray[i]['func'](funcArray[i]['vars']);
                        }, mili * i);
                    }
               });
            });

2 个答案:

答案 0 :(得分:0)

您需要async/awaitPromise来处理节点js中的异步操作。 我不确定你是否有支持Async / await的节点版本,所以我尝试了基于promise的解决方案。

query.on('end', () => {
    connection.release();
    writeArray = itemArray.slice(0),
        alteredArray = [];
    var csv = json2csv({ data: writeArray, fields: fields }),
        timestamp = new Date(Date.now());
    timestamp = timestamp.getFullYear() + '-' + (timestamp.getMonth() + 1) + '-' + timestamp.getDate() + ' ' + timestamp.getHours() + ':' + timestamp.getMinutes() + ':' + timestamp.getSeconds();
    let fpath = './public/assets/archives/opalEdiInventory-' + timestamp + '.csv';

    var calls = chunk(itemArray, 1000)
                        .map(function(chunk) {
                            var renameditemsArray = chunk.map((item) => new renamedItem(item, warehouse));
                            var postOptions = {};
                            postOptions.url = endpoint;
                            postOptions.body = JSON.stringify({
                                login: user,
                                password: password,
                                items: renameditemsArray
                            });
                            return postOptions;
                        });
    sequenceBatch(calls, makeRequest)
        .then(function() {
            console.log('done');
        })
        .catch(function(err) {
            console.log('failed', err)
        });

    function sequenceBatch (calls, cb) {
        var sequence = Promise.resolve();
        var count = 1;
        calls.forEach(function (callOptions) {
            count++;
            sequence = sequence.then(()=> {
                return new Promise(function (resolve, reject){
                    setTimeout(function () {
                        try {
                            cb(callOptions);
                            resolve(`callsequence${count} done`);
                        }
                        catch(err)  {
                            reject(`callsequence ${count} failed`);
                        }
                    }, 180000);
                });
            })
        });
        return sequence;
    }
    function makeRequest(postOptions) { 
        request(postOptions, (err, res, body) => {
            if (err) {
                console.error(err);
                throw err; 
            }
            console.log(body)
        });
    }

    function chunk(arr, len) {
        var chunks = [],
            i = 0,
            n = arr.length;
        while (i < n) {
            chunks.push(arr.slice(i, i += len));
        }
        return chunks;
    }

    function renamedItem(item, warehouse) {
        this.sku = item['sku']
        this.quantity = item["quantity"]
        this.overstockquantity = item["osInv"]
        this.warehouse = warehouse
        this.isdiscontinued = item["disc"]
        this.backorderdate =  item["etd"]
        this.backorderavailability=  item["boq"]
    }
});

你可以试试这个片段并让我知道它是否有效吗?我无法测试它,因为它是在飞行中制作的。核心逻辑在sequenceBatch函数中。答案基于另一个question,它解释了超时和承诺如何协同工作。

答案 1 :(得分:0)

根本没有关闭或异步问题,我正在构建的请求对象使用对象的引用而不是浅拷贝,导致数据全部链接到结束数组中的同一对象ref。