Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/35.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js 使用nodejs如何返回包含循环中一批API调用中所有数据的对象?_Node.js_Callback - Fatal编程技术网

Node.js 使用nodejs如何返回包含循环中一批API调用中所有数据的对象?

Node.js 使用nodejs如何返回包含循环中一批API调用中所有数据的对象?,node.js,callback,Node.js,Callback,我知道JavaScript中有闭包和回调,但很明显,我没有直观地理解它们 我有一个从API中抓取数据的小应用程序,我可以轻松地控制台。记录每个请求的响应,我的问题是我试图收集数据并构建一个对象,以便在所有请求完成后保存到文件中 我知道nodejs是一个执行的单线程,它不会阻塞,但我不知道在所有内部请求完成后将回调放在哪里,我可以console.logbuilded对象。您将看到我的控制台。日志行位于错误的位置,并在来自内部请求的第一个响应之前执行 细分 获取国家数据 循环countryRespo

我知道JavaScript中有闭包和回调,但很明显,我没有直观地理解它们

我有一个从API中抓取数据的小应用程序,我可以轻松地
控制台。记录每个请求的响应,我的问题是我试图收集数据并构建一个对象,以便在所有请求完成后保存到文件中

我知道nodejs是一个执行的单线程,它不会阻塞,但我不知道在所有内部请求完成后将回调放在哪里,我可以
console.log
builded对象。您将看到我的
控制台。日志
行位于错误的位置,并在来自内部请求的第一个响应之前执行

细分

  • 获取国家数据
  • 循环countryResponse并使用每个国家id获取详细信息
  • 将每个细节添加到数组中
  • 当所有请求完成时,将数组添加到对象
  • 代码

    const limit = require("simple-rate-limiter");
    
    let request = limit(require("request")).to(1).per(200);
    
    
    let options = {
        method: 'POST',
        url: 'https://myendpoint/details',
        headers: {
            'cache-control': 'no-cache',
            'Content-Type': 'application/json'
        },
        body: {
            "token": "TOKEN",
            "method": "countries"
        },
        json: true
    };
    
    global.package = {};
    global.services = {};
    let countryServices = [];
    
    /*
        Country fetch
    */
    request(options, function (err, response, countryResponse) {
        if (err) {}
    
        package.countries = countryResponse;
    
        countryResponse.forEach(function (entry) {
    
            let innerOptions = {
                method: 'POST',
                url: 'https://myendpoint/details',
                headers: {
                    'cache-control': 'no-cache',
                    'Content-Type': 'application/json'
                },
                body: {
                    "token": "TOKEN",
                    "method": "services"
                },
                json: true
            };
            //THIS LINE OMG
            //let countryServices = [];
    
            innerOptions.body.countryCode = entry.countryCode;
    
            request(innerOptions, function (err, response, innerResponse) {
                if (err) {}
    
                countryServices.push(innerResponse);
                console.log(" inner response " + entry.countryCode + ' : ' + JSON.stringify(innerResponse, null, ""));
    
            });//END innerResponse
        });//END countryResponse.forEach
        services = countryServices;
        console.log(JSON.stringify(package, null, ""));
        console.log(JSON.stringify(countryServices, null, ""));
    });//END orderResponse
    
    [
        {
            "countryCode": 1,
            "countryName": "Virgin Islands (U.S.)"
        },
        {
            "countryCode": 7,
            "countryName": "Russian Federation"
        }
    ]
    
    [
        {
            "Type": "1",
            "id": 2
        },
        {
            "Type": "2",
            "id": 3
        }
    ]
    
    countryResponse

    const limit = require("simple-rate-limiter");
    
    let request = limit(require("request")).to(1).per(200);
    
    
    let options = {
        method: 'POST',
        url: 'https://myendpoint/details',
        headers: {
            'cache-control': 'no-cache',
            'Content-Type': 'application/json'
        },
        body: {
            "token": "TOKEN",
            "method": "countries"
        },
        json: true
    };
    
    global.package = {};
    global.services = {};
    let countryServices = [];
    
    /*
        Country fetch
    */
    request(options, function (err, response, countryResponse) {
        if (err) {}
    
        package.countries = countryResponse;
    
        countryResponse.forEach(function (entry) {
    
            let innerOptions = {
                method: 'POST',
                url: 'https://myendpoint/details',
                headers: {
                    'cache-control': 'no-cache',
                    'Content-Type': 'application/json'
                },
                body: {
                    "token": "TOKEN",
                    "method": "services"
                },
                json: true
            };
            //THIS LINE OMG
            //let countryServices = [];
    
            innerOptions.body.countryCode = entry.countryCode;
    
            request(innerOptions, function (err, response, innerResponse) {
                if (err) {}
    
                countryServices.push(innerResponse);
                console.log(" inner response " + entry.countryCode + ' : ' + JSON.stringify(innerResponse, null, ""));
    
            });//END innerResponse
        });//END countryResponse.forEach
        services = countryServices;
        console.log(JSON.stringify(package, null, ""));
        console.log(JSON.stringify(countryServices, null, ""));
    });//END orderResponse
    
    [
        {
            "countryCode": 1,
            "countryName": "Virgin Islands (U.S.)"
        },
        {
            "countryCode": 7,
            "countryName": "Russian Federation"
        }
    ]
    
    [
        {
            "Type": "1",
            "id": 2
        },
        {
            "Type": "2",
            "id": 3
        }
    ]
    
    内部响应

    const limit = require("simple-rate-limiter");
    
    let request = limit(require("request")).to(1).per(200);
    
    
    let options = {
        method: 'POST',
        url: 'https://myendpoint/details',
        headers: {
            'cache-control': 'no-cache',
            'Content-Type': 'application/json'
        },
        body: {
            "token": "TOKEN",
            "method": "countries"
        },
        json: true
    };
    
    global.package = {};
    global.services = {};
    let countryServices = [];
    
    /*
        Country fetch
    */
    request(options, function (err, response, countryResponse) {
        if (err) {}
    
        package.countries = countryResponse;
    
        countryResponse.forEach(function (entry) {
    
            let innerOptions = {
                method: 'POST',
                url: 'https://myendpoint/details',
                headers: {
                    'cache-control': 'no-cache',
                    'Content-Type': 'application/json'
                },
                body: {
                    "token": "TOKEN",
                    "method": "services"
                },
                json: true
            };
            //THIS LINE OMG
            //let countryServices = [];
    
            innerOptions.body.countryCode = entry.countryCode;
    
            request(innerOptions, function (err, response, innerResponse) {
                if (err) {}
    
                countryServices.push(innerResponse);
                console.log(" inner response " + entry.countryCode + ' : ' + JSON.stringify(innerResponse, null, ""));
    
            });//END innerResponse
        });//END countryResponse.forEach
        services = countryServices;
        console.log(JSON.stringify(package, null, ""));
        console.log(JSON.stringify(countryServices, null, ""));
    });//END orderResponse
    
    [
        {
            "countryCode": 1,
            "countryName": "Virgin Islands (U.S.)"
        },
        {
            "countryCode": 7,
            "countryName": "Russian Federation"
        }
    ]
    
    [
        {
            "Type": "1",
            "id": 2
        },
        {
            "Type": "2",
            "id": 3
        }
    ]
    

    最简洁、最直接的方法可能是
    async/await
    way。您可以手动提示
    请求
    并用简单延迟替换
    简单速率限制器
    相关性:

    “严格使用”;
    const request=require('request');
    功能承诺请求(选项){
    返回新承诺((解决、拒绝)=>{
    请求(选项,(错误、响应、正文)=>{
    如果(错误)拒绝(错误);
    其他决议(机构);
    });
    });
    }
    功能延迟(毫秒){
    返回新承诺((resolve)=>{setTimeout(resolve,ms);});
    }
    常量选项={
    方法:“POST”,
    网址:'https://myendpoint/details',
    标题:{
    “缓存控制”:“无缓存”,
    “内容类型”:“应用程序/json”,
    },
    正文:{
    令牌:“令牌”,
    方法:“国家”,
    },
    是的,
    };
    (异步函数main(){
    试一试{
    const countryResponse=等待承诺请求(选项);
    常量innerRequests=[];
    for(countryResponse的常量输入){
    常量innerOptions={
    方法:“POST”,
    网址:'https://myendpoint/details',
    标题:{
    “缓存控制”:“无缓存”,
    “内容类型”:“应用程序/json”,
    },
    正文:{
    令牌:“令牌”,
    方法:“服务”,
    countryCode:entry.countryCode,
    },
    是的,
    };
    const innerRequest=promisifiedRequest(innerOptions);
    innerRequests.push(innerRequest);
    等待延迟(200);
    }
    const countryServices=wait Promise.all(内部请求);
    log(JSON.stringify(countryServices,null');
    }捕捉(错误){
    控制台错误(err);
    }
    })();
    
    如果您需要更多背景信息或需要扩展应用程序(添加具有更复杂速率限制的并行请求),这些资料将非常有用:


    代码末尾的
    控制台.log
    s不会等到
    forEach
    启动的所有异步操作完成后才运行。您需要引入某种机制,等待forEach触发的所有函数完成它们的请求

    如果您想坚持使用回调,那么可以考虑使用类似的
    each
    方法,它将为您处理这种情况

    通常使用和来处理此问题。如果您使用的是,您的示例将如下所示,假设Node.js的版本相当最新(选项省略):

    const request=require('request-promise');
    异步函数run(){
    常量选项={};
    const countryServices=[];
    const countryResponse=等待请求(选项);
    for(const country of countryResponse){
    const innerOptions={};
    const innerResponse=等待请求(innerOptions);
    countryServices.push(内部响应);
    }
    console.log(countryServices);
    }
    run();
    

    这比使用回调要清楚一点,for-of循环的行为完全符合您的预期。

    谢谢您,我肯定有很多东西需要学习,我看到了很多阅读材料。我注意到一件事,在我天真的方法中,它完成了运行约19秒,但您的解决方案是约85秒。这是因为您的请求是异步的,只有在前一个请求完成+200ms延迟后才会发出请求;像我这样的人,每200毫秒会在哪里发出一次请求?是的。我可以尝试编辑以实现相同的行为。稍后我会添加一条评论。你能尝试一下新的变体并做一些小的改动吗?是的,最多20秒!:)我花了一分钟才看到您构建了一个
    promisifiedRequest
    s数组,然后调用了
    Promise。所有这些都是
    。非常感谢,我有很多事情要考虑,并将根据响应添加更多嵌套调用。@chrisloughnane Happy coding)