简体   繁体   中英

How to do promise inside promise

I am trying to do pagination with promise. Here's my workflow.

Step 1 : Total page in pagination is 50. The url will be like url?page=1

Step 2 : In each page i will get 50 products, which i need to call a seperate api.

The only condition is, during pagination, the second page should called only if first page's 50 api call is done. Once all the 50 pages are fetched, it should return the promise.

What i have so far is.

let promises = [];
paginate(50);
Promise.all(promises)
  .catch(function(err) {
  console.log('err',err);
  })
  .then(() => {
    console.log('All Done!!!!!');
});

function paginate(loop){
promises.push(
    axios(config)
    .then(function (response) {
        // Got 50 products
    })
    .catch(function (error) {
      console.log('err',err);
    })
)

In the place Got 50 products i need to still iterate the 50 products in axios. I am not sure whether it is possible to do promise inside promise.

As the server can't bear all sudden loads, the only condition is to iterate the second 50 products (or next page's products) only after first (or previous 50 api is called).

Edit :

// Here i have got 50 products As i told, On each page i will get 50 products, i will call another api for all those 50 products. I have given the code below.

Only constraint is on first page response, the response 50's api should be called.. it's like product?product=1 . the next 50 should be called only after first 50's api called

for (let index = 0; index < response.length; index++) {
const element = response[index];
    //Here call api for one item 
    axios(config)
    .then(function (elemen t) {
        // Here i have got 50 products
    })
    .catch(function (error) {
      console.log('err',err);
    })
}

You're probably not looking for Promise.all (which is meant for running things in parallel) , but for recursion:

 fetchPages(0, 49) .then(console.log); function fetchPages(from, to, results = []) { if (from <= to) { return fetchPage(from) .then(res => results.push(...res)) .then(() => fetchPages(from + 1, to, results)); // calls itself } else { return results; } } function fetchPage(n) { console.log(`Fetching page ${n}`); // Here, you would return axios()... // But just for this demo, I fake that: const results = new Array(50).fill(null) .map((_,i) => `Product ${i} from page ${n}`); return new Promise(resolve => setTimeout(() => resolve(results), 100)); }


Edit

The code above solves the problem of pages needing to be fetched only one after the other. We can keep the fetchPages function as it is. Now, since every page will contain products which will need to be fetched individually, we'll just edit fetchPage a bit.

There are multiple ways this could be done. Here are some:

Solution A: fetch every product in parallel

If the server can handle 50 requests going off at once, you could use Promise.all :

function fetchPage(n) {
  console.log(`Fetching page ${n}`);
  return axios(`/page?page=${n}`)
         .then(productIds => {
           return Promise.all(productIds.map(fetchProduct));
         });
}

function fetchProduct(id) {
  return axios(`/product?product=${id}`);
}

Solution B: fetch every product in sequence

If the server can't handle multiple requests going off at once, you could use recursion once again:

function fetchPage(n) {
  console.log(`Fetching page ${n}`);
  return axios(`/page?page=${n}`)
         .then(fetchproducts);
}

function fetchProducts(productIds, results = []) {
  if (productIds.length) {
    const productId = productIds.shift();
    return fetchProduct(productId)
           .then(res => results.push(res))
           .then(() => fetchProducts(productIds, results)); // calls itself
  } else {
    return results;
  }
}

function fetchProduct(id) {
  return axios(`/product?product=${id}`);
}

Solution C: fetch products X requests at a time

If the server can handle X requests going off at once, you could use a module like queue , which can help you with concurrency:

const queue = require('queue'); // Don't forget to $ npm install queue
const MAX_CONCURRENT_CALLS = 4; // 4 calls max at any given time

function fetchPage(n) {
  console.log(`Fetching page ${n}`);
  return axios(`/page?page=${n}`)
         .then(fetchproducts);
}

function fetchProducts(productIds) {
  const q = queue();
  q.concurrency = MAX_CONCURRENT_CALLS;
  const results = [];

  q.push(
    ...productIds.map(productId => () => {
      return fetchProduct(productId)
             .then(product => results.push(product));
    })
  );

  return new Promise((resolve, reject) => {
    q.start(function (err) {
      if (err) return reject(err);
      resolve(results);
    });
  });
}

function fetchProduct(id) {
  return axios(`/product?product=${id}`);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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