.then()异步内部的while循环

时间:2020-01-16 15:48:33

标签: javascript ecmascript-6

我最近遇到了一个有趣的问题,我无法解决自己的生活。我正在调用将记录分成页面的API调用,页面的信息位于响应头中。因此,我希望能够再次调用以检索数据和下一个标头,直到没有更多响应标头为止。

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;
      }

我需要放入某种循环的部分是基于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);
            }
          })
      );

预先感谢您看我可怜的问题

2 个答案:

答案 0 :(得分:2)

尝试使用递归;像这样的东西:

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 */
    })

答案 1 :(得分:1)

使用异步递归函数。
我不确定您的api返回什么,但这应该可以工作:
首先,只要找到元素就可以返回它,如果元素太多,则可以节省一些迭代。

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;
}

接下来定义您的主要通话:

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.
}

然后循环

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.
}

现在您需要做的就是调用主函数:

main();
//or: 
//await main();
//if you want to wait for it.
//You need to call it from within an async function.