我正在对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");
});
我建议使用 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()
描述 此处.
你也可以将承诺保存在一个数组中,如果顺序很重要的话,可以在每个承诺完成后访问它们
const promises = []
promises.push(...)
Promise.all(promises).then(data -> ....)
数据现在将是一个包含各个承诺结果的数组。你可以随意合并或处理它们.请注意,上述函数只有在所有先前的承诺被解析后才会解析。
你可以尝试检查当前的循环索引,并在最后一个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模板字符串中的小错误... ...
fetch是一个异步调用。当调用fetch是移动到事件堆栈并等待响应(你的表没有更新)。
同时,文件读取是以一个空数组来执行的。很明显,你只得到一个空数组