首页 > 解决方案 > for循环nodejs中的异步

问题描述

我正在尝试访问 api,我将不得不根据需要迭代的页码多次运行 api 调用,以下是我正在使用的代码以及如何将所有响应推送到数组中.

由于 nodeJs 是单线程的,它不等待来自 api 的响应。我该如何解决这个问题并确保所有响应值都被推送到数组中

在 for 循环中,我想要包含 api 响应的所有值的最终数组。所以,我检查总页值和响应页码是否匹配,这意味着这将是最后一页,我将数组推送到另一个函数,但是当我这样做时,它没有所有值,因为 nodejs 不等待api 响应。

const fs = require('fs');
var pepKey = 'asdfasdfasd';
var pepResponse;

var pepTimecards = [];
pep();


function pep(){
    var options = {
        headers: {
            "content-type": "application/json",
        },
        agentOptions: {
            pfx: fs.readFileSync('./certificate/asdfsdaf.p12'),
            passphrase: 'asdasdsda'
        }
    };

    request.get('https://source.asdfasdf.io/api/organisations/asdfasdf/timecard_keys?timecard_type=Flex',options,  (err, res, body) => {
      if (err) { return console.log(err); }
      pepResponse = JSON.parse(body)

    pepTimecards = pepResponse.data;
      if(pepResponse.pages > 1){
         for(let i=2;i<=pepResponse.pages;i++){

            var url = 'https://source.`pepme`.io/api/organisations/sdfsadf/timecard_keys?timecard_type=Flex&page='+pageNo;
            request.get(url,options,  (err, res, body) => {
                if (err) { return console.log(err); }
                body = JSON.parse(body)
                pepTimecards = pepTimecards.concat(body.data)
                if(pepResponse.pages == body.page){
                    console.log(pepResponse.pages)
                    console.log(body.page +"body page")
                    console.log(pepTimecards)
                }
              });


        }


      }else{

      }  
    });
}

标签: arraysnode.jsfor-loopasynchronous

解决方案


使用 request-promise 库,它提供了请求库的承诺版本。然后,您可以在 for循环中使用 async/await 来序列化您的操作:

更新的答案与 OP 问题中的编辑代码一起使用

const fs = require('fs');
const rp = require('request-promise');
const pepKey = 'asdfasdfasd';

pep().then(pepTimecards => {
    // the timecard data is valid in here
    console.log(pepTimecards);
}).catch(err => {
    console.log(err);
});


async function pep() {
    let timecards = [];
    const options = {
        headers: {
            "content-type": "application/json",
        },
        agentOptions: {
            pfx: fs.readFileSync('./certificate/asdfsdaf.p12'),
            passphrase: 'asdasdsda'
        },
        json: true,
        uri: 'https://source.asdfasdf.io/api/organisations/asdfasdf/timecard_keys?timecard_type=Flex'
    };

    let pepResponse = await rp(options);

    timecards = pepResponse.data;
    if (pepResponse.pages > 1) {
        for (let i = 2; i <= pepResponse.pages; i++) {
            options.uri = 'https://source.`pepme`.io/api/organisations/sdfsadf/timecard_keys?timecard_type=Flex&page='+pageNo;
            let body = await rp(url, options);
            // add body.data onto the existing array
            timecards.push(...body.data);
        }
    } else {

    }
    console.log(pepResponse.pages)
    console.log(timecards)
    return timecards;
}

OP 在他们的问题中编辑代码之前的先前答案:

const rp = require('request-promise');

// I'm assuming this is some sort of method definition on a class, otherwise it needs the function keyword
async pageno(pageNo) {
    for (let i=2;i<=pepResponse.pages;i++){
        try {
            options.uri = 'https://test/timecard_keys?timecard_type=asdas&page='+pageNo;
            // let request-promise parse the json for you automatically
            options.json = true;
            let body = await rp(options);
            pepTimecards = pepTimecards.concat(body.data)
            if (pepResponse.pages == body.page){
                console.log(pepResponse.pages)
                console.log(body.page +"body page")
                console.log(pepTimecards)
            }
        } catch(e) {
            // decide what to do for error handling
            // this will log and rethrow so the caller will get a rejected promise
            console.log(e);
            throw e;
        }
    }
    // return some value here to be the resolved value of the returned promise
    return pepTimecards;
}

在您的代码中,不清楚options, pepTimecards,pepResponse变量的声明位置。它们可能应该在这里声明为局部变量或传递给函数和/或从你的函数返回。


修改总结:

  1. 添加async到方法声明,以便我们可以使用await.
  2. 将 request-promise 库加载到rp变量中
  3. 添加options.json = true到让 request-promise 库自动为我们解析 JSON 结果
  4. 更改rp()为仅使用选项结构(向其中添加 URL)
  5. 添加 try/catch 以捕获来自 的任何错误await,记录它们,然后重新抛出,这样pageno()将返回一个承诺,如果有错误则拒绝(如果需要,您可以自定义出现错误时的行为)
  6. 添加一个返回值,以便对 Promise 有有意义的解析值(您不应该像现在这样使用副作用编程(修改未传入、在本地声明或返回的变量)。

您仍然需要解决的问题:

  1. 停止使用副作用编程来修改未传入、未在本地声明且未返回的自由变量。这是设计代码的不好方法。您没有从调用代码或定义这些其他变量的位置显示足够的整体上下文,以就应该如何完成提出具体建议。
  2. 如果其中一个请求出现错误,请确定您的错误处理策略是什么,并实施该策略并进行适当的处​​理。

推荐阅读