如何在 promise 中实现 promise
How to do promise inside promise
我正在尝试使用 promise 进行分页。这是我的工作流程。
第 1 步:分页总页数为 50。url 将类似于 url?page=1
第 2 步: 在每个页面中,我将获得 50 个产品,我需要将其称为单独的 api。
唯一的条件是,在分页期间,仅当第一页的 50 api 调用完成后,才应调用第二页。获取所有 50 页后,它应该 return 承诺。
我目前所掌握的是
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);
})
)
在 Got 50 products
的地方,我仍然需要迭代 axios 中的 50 个产品。我不确定是否可以在承诺中做承诺。
由于服务器无法承受所有突如其来的负载,唯一的条件是只有在第一个(或前50个api被调用之后)才迭代第二个50个产品(或下一页的产品)。
编辑:
// 这里我有 50 个产品
正如我所说,在每个页面上我将获得 50 种产品,我将为所有这 50 种产品调用另一个 api。我已经给出了下面的代码。
唯一的限制是第一页响应,应该调用响应 50 的 api.. 就像 product?product=1
。接下来的 50 个应该只在前 50 个 api 被调用
之后被调用
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);
})
}
您可能不是在寻找 Promise.all
(这意味着 运行 并行),但对于递归:
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));
}
编辑
上面的代码解决了页面只需要一个接一个获取的问题。我们可以保持 fetchPages
功能不变。现在,由于每个页面都包含需要单独获取的产品,我们只需编辑一下 fetchPage
。
有多种方法可以做到这一点。这里有一些:
解决方案 A:并行获取每个产品
如果服务器可以同时处理 50 个请求,您可以使用 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}`);
}
解决方案 B:按顺序获取每个产品
如果服务器无法同时处理多个请求,您可以再次使用递归:
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}`);
}
解决方案 C:一次获取 X 个请求的产品
如果服务器可以同时处理 X 个请求,您可以使用像 queue 这样的模块,它可以帮助您实现并发:
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}`);
}
我正在尝试使用 promise 进行分页。这是我的工作流程。
第 1 步:分页总页数为 50。url 将类似于 url?page=1
第 2 步: 在每个页面中,我将获得 50 个产品,我需要将其称为单独的 api。
唯一的条件是,在分页期间,仅当第一页的 50 api 调用完成后,才应调用第二页。获取所有 50 页后,它应该 return 承诺。
我目前所掌握的是
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);
})
)
在 Got 50 products
的地方,我仍然需要迭代 axios 中的 50 个产品。我不确定是否可以在承诺中做承诺。
由于服务器无法承受所有突如其来的负载,唯一的条件是只有在第一个(或前50个api被调用之后)才迭代第二个50个产品(或下一页的产品)。
编辑:
// 这里我有 50 个产品 正如我所说,在每个页面上我将获得 50 种产品,我将为所有这 50 种产品调用另一个 api。我已经给出了下面的代码。
唯一的限制是第一页响应,应该调用响应 50 的 api.. 就像 product?product=1
。接下来的 50 个应该只在前 50 个 api 被调用
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);
})
}
您可能不是在寻找 Promise.all
(这意味着 运行 并行),但对于递归:
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));
}
编辑
上面的代码解决了页面只需要一个接一个获取的问题。我们可以保持 fetchPages
功能不变。现在,由于每个页面都包含需要单独获取的产品,我们只需编辑一下 fetchPage
。
有多种方法可以做到这一点。这里有一些:
解决方案 A:并行获取每个产品
如果服务器可以同时处理 50 个请求,您可以使用 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}`);
}
解决方案 B:按顺序获取每个产品
如果服务器无法同时处理多个请求,您可以再次使用递归:
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}`);
}
解决方案 C:一次获取 X 个请求的产品
如果服务器可以同时处理 X 个请求,您可以使用像 queue 这样的模块,它可以帮助您实现并发:
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}`);
}