如何在for循环中等待每次迭代并在nodeJS中将响应作为API响应返回

Posted

技术标签:

【中文标题】如何在for循环中等待每次迭代并在nodeJS中将响应作为API响应返回【英文标题】:How to wait for each iteration in for loop and return response as API response in nodeJS 【发布时间】:2018-02-27 20:42:40 【问题描述】:

我正在使用 for 循环遍历元素数组并在 for 循环内调用具有不同参数的相同函数。这是我的代码:

exports.listTopSongs = function(query) 
    return new Promise(function(resolve, reject) 
        var str = query.split(","), category,
        for(var i=0; i<str.length; i++) 
           sampleFn(str[i], 'sample', resolve, reject);
        
    );
;

function sampleFn(lang, cat, resolve, reject) 
        client.on("error", function (err) 
            console.log(err);
            var err = new Error('Exception in redis client connection')
            reject(err);                                
        );
        client.keys(lang, function (err, keys)
            if (err) return console.log(err);
            if(keys.length != 0) 
                client.hgetall(keys, function (error, value) 
                    var objects = Object.keys(value);
                    result['title'] = lang;
                    result[cat] = [];
                    var x =0;
                    for(x; x<objects.length; x++) 
                        var val = objects[x];
                            User.findAll(attributes: ['X', 'Y', 'Z'],
                                where: 
                                    A: val
                                
                            ).then(data => 
                                if(data != null) 
                                    //some actions with data and stored it seperately in a Json array
                                    if(result[cat].length == objects.length) 
                                        resolve(result);
                                    
                                 else 
                                    console.log(""+cat+" is not avilable for this value "+data.dataValues['X']);
                                
                            );
                    
               );
         );
   

这里它不会等待第一次迭代完成。它只是在完成第一次迭代功能之前异步运行。我需要将结果作为结果返回:[ 1, 2, 3,4]。但它无缝运行并在完成所有操作之前返回空对象或仅返回一个对象。如何解决。

我使用了节点异步循环。但它使用下一个,我无法在使用该包时发送我的参数。请帮帮我

【问题讨论】:

检查“aync”包。它有许多使 for 循环同步运行的功能。 你使用的是哪个node js版本? 我使用的是节点 8.4.0 好的,@ShubhamJain 会尽力让你知道 【参考方案1】:

Async 提供了允许这样做的控制流方法。

使用async.each:

async.each(openFiles, function(file, callback) 

    // Perform operation on file here.
    console.log('Processing file ' + file);

    if( file.length > 32 ) 
      console.log('This file name is too long');
      callback('File name too long');
     else 
      // Do work to process file here
      console.log('File processed');
      callback();
    
, function(err) 
    // if any of the file processing produced an error, err would equal that error
    if( err ) 
      // One of the iterations produced an error.
      // All processing will now stop.
      console.log('A file failed to process');
     else 
      console.log('All files have been processed successfully');
    
);

【讨论】:

【参考方案2】:

如果您不想使用库,可以自己编写代码。这也会很有启发性。我接受了您的问题并编写了一个虚拟异步循环:

function listTopSongs(query) 
    return new Promise(async(resolve, reject) =>  //add async here in order to do asynchronous calls
        const str = query.split(",") //str is const, and the other variable was not used anyway
        
        for( let i = 0;i < str.length; i++) 
            const planet = await sampleFn(str[i], 'sample', resolve, reject)
            console.log(planet)
        
    );
;

function sampleFn(a, b, c, d) 
    return fetch(`https://swapi.co/api/planets/$a/`)
        .then(r => r.json())
        .then(rjson => (a + " : " + rjson.name))


listTopSongs("1,2,3,4,5,6,7,8,9")

我使用了一些虚拟的星球大战 API 来伪造一个长期承诺,但它应该适用于您的 sampleFn。小心,如果你有像示例中那样的网络调用,它会非常非常慢。

编辑:我运行了你的代码,发现有一些错误:你的承诺中没有解决,所以它不是一个 thenable (https://developer.mozilla.org/en-US/docs/Web/javascript/Reference/Global_Objects/Promise/resolve see thenable )

这是一个完整的工作代码。好的部分:不需要库,没有依赖项。

//for node.js, use node-fetch :
//const fetch = require("node-fetch")

function listTopSongs(query) 
    return new Promise(async(resolve, reject) =>  //add async here in order to do asynchronous calls
        const str = query.split(",") //str is const, and the other variable was not used anyway
        const planets = []
        for (let i = 0; i < str.length; i++) 
            const planet = await sampleFn(i + 1, str[i], resolve, reject)
            planets[i] = planet
            console.log(planet)
        
        resolve(planets)
    );
;

function sampleFn(a, b, c, d) 
    return fetch(`https://swapi.co/api/planets/$a/`)
        .then(r => r.json())
        .then(rjson => (a + b + " : " + rjson.name))


listTopSongs("a,b,c,d").then(planets => console.log(planets))

【讨论】:

我无法将我的 json 数组从函数 sampleFn 返回到 listTopSongs【参考方案3】:

由于你使用的是promise,你可以做这样的事情

exports.listTopSongs = function(query) 
    return Promise.resolve(true).then(function()
        var str = query.split(",");
        var promises = str.map(function(s)
            return sampleFn(str[i], 'sample');
        );
        return Promise.all(promises);
    ).then(function(results)
       //whatever you want to do with the result
    );
;

为此,您必须将 sampleFn 更改为不依赖外部解析和拒绝函数。我看不出使用外部解决和拒绝的原因。为什么不使用 Promise.Resolve, Promise.Reject;

【讨论】:

以上是关于如何在for循环中等待每次迭代并在nodeJS中将响应作为API响应返回的主要内容,如果未能解决你的问题,请参考以下文章

每次while/for循环迭代后如何等待一秒钟?

NodeJS,如何强制异步 for 循环在传递到下一次迭代之前等待 HTTP 请求解决,这样我们就不会收到 EMFILE 错误?

如何在循环的每次迭代中将新图形保存为 png

在 Photoshop 脚本中,如何循环每个选择并在每次迭代期间应用渐变效果?

在 for 循环中将数据帧附加在一起

如何在javascript中将动态ID放在复选框中?