如何将承诺返回的数据推送到一个数组中?

问题描述 投票:0回答:1

我正在对Udemy API进行调用。为了同时进行调用,我使用了一个循环。通过这样做,我自动递增页码,并试图从每个页面获取数据并将其存储到一个数组中,这样我就可以将所有数据写入一个json格式的文件中。但我得到的只是一个空数组。我如何访问promise返回的值并存储到doc.table数组中?

我的代码。

const fetch=require("node-fetch");
const fs=require("fs");
let doc={};
doc.table=[];

for(let i=1;i<=10;i++){

fetch('https://www.udemy.com/api-2.0/courses/ page='+i+'&page_size=10&client_id=${client_id}&client_secret=${client_secret},{
      method:'GET',
      body:null,
      headers:{authorization: ${auth_code}}
      })
      .then(res=>res.json())
      .then(json=>doc.table.push(json))
};


fs.writeFile("UDEMY.json",JSON.stringify(doc),function(err){
    if(err) throw err;
    console.log("Complete");
});
javascript node.js json es6-promise fetch-api
1个回答
2
投票

我建议使用 await 以致于 for 循环将在每次迭代时暂停。

const fetch = require("node-fetch");
const fsp = require("fs").promises;

let doc = { table: []};

async function run() {
    for (let i = 1; i <= 10; i++) {

        let data = await fetch('https://www.udemy.com/api-2.0/courses/ page='+i+'&page_size=10&client_id=${client_id}&client_secret=${client_secret},{
              method:'GET',
              body:null,
              headers:{authorization: ${auth_code}}
        }).then(res=>res.json());

        doc.table.push(data);
    }

    await fsp.writeFile("UDEMY.json",JSON.stringify(doc));
    console.log("done");
}

run().catch(err => {
    console.log(err);
});

另一种可能是并行运行所有的请求,并使用... Promise.all() 以知道它们何时全部完成。 这两个解决方案的关键是使用承诺,即 fetch() 返回到控制知道什么时候完成。

如果你真的想并行运行它们,并且你确信你的目标主机会允许,你可以这样做。

const fetch = require("node-fetch");
const fsp = require("fs").promises;

let doc = { table: []};

function run() {
    let promises = [];
    for (let i = 1; i <= 10; i++) {

        promises.push(fetch('https://www.udemy.com/api-2.0/courses/ page='+i+'&page_size=10&client_id=${client_id}&client_secret=${client_secret},{
              method:'GET',
              body:null,
              headers:{authorization: ${auth_code}}
        }).then(res=>res.json()));

    }
    return Promise.all(promises).then(data => {
        doc.table = data;
        return fsp.writeFile("UDEMY.json",JSON.stringify(doc));
    });

}

run().then(() => {
    console.log('done');
}).catch(err => {
    console.log(err);
});

如果你想要某种程度的并行请求,但又想限制多少个并行请求,你可以使用以下方法 mapConcurrent() 描述 此处.


0
投票

你也可以将承诺保存在一个数组中,如果顺序很重要的话,可以在每个承诺完成后访问它们

const promises = []
promises.push(...)
Promise.all(promises).then(data -> ....)

数据现在将是一个包含各个承诺结果的数组。你可以随意合并或处理它们.请注意,上述函数只有在所有先前的承诺被解析后才会解析。


0
投票

你可以尝试检查当前的循环索引,并在最后一个Promise fullfillment内写入你的文件。

const fetch = require('node-fetch');
const fs = require('fs');

let url;
let counter = 10;
const doc = {
  table: []
};

for (let i = 1; i <= 10; i++) {
  url = `https://www.udemy.com/api-2.0/courses/page=${i}&page_size=10&client_id=${client_id}&client_secret=${client_secret}`;
  fetch(url, {
    method: 'GET',
    body: null,
    headers: {
      authorization: auth_code
    }
  })
  .then(res => res.json())
  .then(json => {
    // next line will not guarantee the order of pages
    // doc.table.push(json);
    // so we can use current loop index and counter
    doc.table[i] = json;
    // when counter is 0 we can write a file 
    if (!--counter) {
      fs.writeFile('UDEMY.json', JSON.stringify(doc), function(err) {
        if (err) {
          throw err;
        }
        console.log("Complete");
      });
    }
  })
};

我还修正了你的URL模板字符串中的小错误... ...


-1
投票

fetch是一个异步调用。当调用fetch是移动到事件堆栈并等待响应(你的表没有更新)。

同时,文件读取是以一个空数组来执行的。很明显,你只得到一个空数组

© www.soinside.com 2019 - 2024. All rights reserved.