我的场景如下:有一个我想要获取的API。API返回一个json,该json有一个名为"assets“的数组。该数组大小始终为20。现在,我这样调用端点:
fetch(
`https://api.example.io/api/v1/assets/?offset=${offset}`
)
其中,如果offset为0,则返回0- 20资产的数组,如果offset为20,则返回20到40,依此类推。
我想检查1000个项目,这意味着我想调用这个fetch 1000/20 = 50次。每当我调用fetch时,我都会循环这20个项目,并将它们插入到我的数据库中。问题是我不能做这样的事情:
let offset=0;
for(let i = 0; i < 50; i++ {
fetch(
`https://api.example.io/api/v1/assets/?offset=${offset}`
)
for(let j = 0; j < 20; j++){
// Insert into DB
}
offset+=20;
}
由于JS的异步特性。每当我尝试这样做时,它都会多次调用fetch,偏移量的值为0,它不会等到嵌套的for循环完成,然后调用20或更晚的40,依此类推……
实现这一行为的正确方法是什么?
发布于 2018-12-04 02:53:57
我从我的一个nodeJS代码库中删除了以下代码,因为它使用异步代码来解决非常类似的问题:
// Throttling is important because you don't want to
// overload the API
const createThrottle = require('async-throttle');
const throttle = createThrottle(2);
// First push all the links into an array using
// the offset
const links = [];
for (let offset = 0; offset < 100; offset += 20) {
links.push(`https://api.example.io/api/v1/assets/?offset=${offset}`);
}
// Next create an array of promises by `map`ing
// over the links using `fetch`.
// Notice I've used throttle here to slow down the hits on
// the API
const promises = links.map(link => throttle(async => () {
const res = await fetch(link);
return await res.json();
}));
// Once all the promises are complete, iterate over their datasets
Promise.all(promises).then(datasets => {
// iterate over datasets
});
发布于 2018-12-04 02:44:01
您可以使用递归或Promises来代替for..loop。
递归::
let insertToDB = function (records, cb) {
if (!records.length) return cb();
let record = records.shift();//assuming records is an array
// Insert record into DB1
insertToDB(records, cb);
};
let loop = function (count, offset, cb) {
if (!count) return cb();
fetch(
`https://api.example.io/api/v1/assets/?offset=${offset}`
)
insertToDB(recordsFromFetch, function () {
offset += 20;
--count;
loop(count, offset, cb)
})
};
loop(50, 0, function () {
console.log("All Done");
})
Promise::我还没有运行它,所以可能有一些语法错误,但是您应该明白了
let insertToDB = function (record) {
return new Promise(function (resolve, reject) {
// Insert record into DB then call resolve
resolve();
})
};
let fetchPhase = function (offset) {
fetch(
`https://api.example.io/api/v1/assets/?offset=${offset}`
)
let dbAll = [];
for (let j = 0; j < 20; j++) {
// assuming you get records from fetch , pass record to be added to db in the parameter
dbAll.push(insertToDB(records[j]))
}
return Promise.all(dbAll)
};
let all = [];
let offset = 0;
for (let i = 0; i < 50; i++) {
all.push(fetchPhase(i));
}
Promise.all(all)
.then(function () {
console.log("ALL DONe");
})
发布于 2018-12-04 02:47:55
为什么不使用Promise.all
const promises = [];
for (let i = 0; i < 10; i++) {
promises.push(
fetch(`https://api.example.io/api/v1/assets/?offset=${i}`)
);
}
Promise.all(promises).then( _results => {
// All fetch calls have completed at this point. _results will be in array of your fetch results.
console.log(results);
// Do db insert here
});
你可以做的一件事就是做一个承诺的function
。在该函数中,让它执行fetch,然后执行db insert all in one函数(使用.then
)。如果您这样做,那么单个Promise.all
调用就可以处理所有事情。如果不这样做,您将不得不再次循环promises并将这些值插入到数据库中。它可能看起来像这样:
const promises = [];
for (let i = 0; i < 10; i++) {
promises.push(fetchAndInsert(i));
}
Promise.all(promises).then( _results => {
console.log(results);
});
function fetchAndInsert(offset) {
return new Promise( (resolve, reject) => {
fetch(`https://api.example.io/api/v1/assets/?offset=${i}`).then (_result => {
// db.insert().then( _result => {
//resolve();
//})
})
})
}
https://stackoverflow.com/questions/53599748
复制相似问题