[英]While loop inside a .then() async
I recently came across an interesting problem that I cannot solve for the life of me.我最近遇到了一个有趣的问题,我一生都无法解决。 I am calling an API call that is breaking up records into pages, the info for the pages reside in the response header.
我正在调用一个将记录分解成页面的 API 调用,页面的信息驻留在响应标头中。 From that, I wanted to be able to do another call to retrieve the data and the next header, until there are no more response headers.
从那以后,我希望能够再次调用以检索数据和下一个标头,直到没有更多响应标头为止。
let parents = {};
const options = {
credentials: "same-origin",
headers: {
accept: "application/json"
},
timeout: 5000
};
fetch(
`/api/v1/courses/200003/enrollments?enrollment_type=ObserverEnrollment&per_page=100`,
options
).then(response =>
response
.json()
.then(data => ({
data: data,
ok: response.ok,
headers: response.headers
}))
.then(res => {
parents = res;
nextURL(res.headers.get("Link"));
let optionsNext = {
credentials: "same-origin",
headers: {
accept: "application/json"
},
timeout: 5000
};
fetch(nextURL(res.headers.get("Link")), optionsNext).then(response =>
response
.json()
.then(data => ({
data: data,
ok: response.ok,
headers: response.headers
}))
.then(res => {
if (res.ok) {
parents.data.push(res.data);
console.info(parents);
}
})
);
})
);
function nextURL(linkTxt) {
let url = null;
if (linkTxt) {
let links = linkTxt.split(",");
let nextRegEx = new RegExp('^<(.*)>; rel="next"$');
for (let i = 0; i < links.length; i++) {
let matches = nextRegEx.exec(links[i]);
if (matches) {
url = matches[1];
}
}
}
return url;
}
The part that I need to put into some kind of loop is the secondary fetch based upon the return of the nextURL function: if !nextURL(res.headers.get("Link"))
I need to break
the loop.我需要放入某种循环的部分是基于 nextURL 函数返回的辅助提取:
if !nextURL(res.headers.get("Link"))
我需要break
循环。
let optionsNext = {
credentials: "same-origin",
headers: {
accept: "application/json"
},
timeout: 5000
};
fetch(nextURL(res.headers.get("Link")), optionsNext).then(response =>
response
.json()
.then(data => ({
data: data,
ok: response.ok,
headers: response.headers
}))
.then(res => {
if (res.ok) {
parents.data.push(res.data);
console.info(parents);
}
})
);
Thanks in advance for even looking at my pitiful problem提前感谢您甚至看着我可怜的问题
Try using recursion;尝试使用递归; something like this:
像这样:
const getFetcher = () => ({
aggregate: [],
run: function (url, options) {
return new Promise((resolve, reject) => {
fetch(url, options)
.then(response => {
const json = response.json();
const { headers, data } = response;
const nextLink = res.headers.get("Link");
this.aggregate.push(data);
if (nextLink) {
this.run(nextLink, options).then(resolve);
}
else {
resolve(this.aggregate);
}
})
})
}
})
const options = {
credentials: "same-origin",
headers: {
accept: "application/json"
},
timeout: 5000
};
const fetcher = getFetcher();
fetcher.run(`/api/v1/courses/200003/enrollments?enrollment_type=ObserverEnrollment&per_page=100`, options)
.then(allPagesData => {
/* at this point you have all the pages data */
})
Use async recursive functions.使用异步递归函数。
I'm not exaclty sure what your api returns but this should work:我不确定您的 api 返回什么,但这应该有效:
Firstly you can just return the element when you find it, it saves you a few iterations if there are too many of them.首先,您可以在找到元素时返回该元素,如果元素过多,它可以为您节省几次迭代。
function nextURL(linkTxt) {
if (linkTxt) {
let links = linkTxt.split(",");
let nextRegEx = new RegExp('^<(.*)>; rel="next"$');
for (let i = 0; i < links.length; i++) {
let matches = nextRegEx.exec(links[i]);
if (matches && matches[1]) {
//return right away
return matches[1];
}
}
}
return null;
}
Next define your main call:接下来定义您的主要调用:
const OPTIONS = {
credentials: "same-origin",
headers: {
accept: "application/json"
},
timeout: 5000
};
let parents = {};
async function main(){
const RESPONSE = await fetch(`/api/v1/courses/200003/enrollments?enrollment_type=ObserverEnrollment&per_page=100`,OPTIONS);
let data = await RESPONSE.json();
let res = {
data: data,
ok: RESPONSE.ok,
headers: RESPONSE.headers
}
loop(res);
//or:
//await loop(res);
//if you want to wait for it.
}
And then your loop然后你的循环
const OPTIONS_NEXT = {
credentials: "same-origin",
headers: {
accept: "application/json"
},
timeout: 5000
};
async function loop(parents){
//if nextURL returns null...
if(nextURL(parents.headers.get("Link")),OPTIONS_NEXT === null)
//...end the loop
return;
//otherwise keep going.
const RESPONSE = await fetch(nextURL(parents.headers.get("Link")),OPTIONS_NEXT);
let data = await RESPONSE.json();
let res = {
data: data,
ok: RESPONSE.ok,
headers: RESPONSE.headers
}
if (res.ok) {
parents.data.push(res.data);
console.info(parents);
}
loop(res);
//or:
//await loop(res);
//if you want to wait for it.
//You need to call it from within an async function.
}
Now all you need to do is call the main function:现在你需要做的就是调用 main 函数:
main();
//or:
//await main();
//if you want to wait for it.
//You need to call it from within an async function.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.