简体   繁体   English

.then() 异步中的 while 循环

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM