从 API 中获取项目的分页列表
Getting a paginated list of items from an API
我需要从 API 端点 (/products) 获取项目列表,但它们是分页的(每页最多 200 个项目)。
我需要创建一个循环来获得 200 个产品,推送到一个数组,并增加页码,这样它就可以请求更多的 200 个产品。当出现404错误(页面不存在)时它会停止,这意味着我得到了所有产品。
我正在使用基于 Promise 的 Axios 来处理请求,但我无法让它工作。我尝试了几种方法,甚至创建了我自己的 Promise,但结果是一样的:
- 无法让它等待所有页面被请求
- 它将始终请求相同的页面,因为页面增量在 .then 的 promise 中(以确保我不会超出最后一页)
我知道 Promises 的想法是异步的,但我正在努力寻找一种方法让它发挥作用。
任何人都知道我可以使用什么逻辑来执行此操作?我只想在继续之前获得所有项目。也许我过于复杂了,一些澄清会很有帮助。
编辑:
尝试递归执行,但执行前结果总是return:
module.exports = {
sync(req, res) {
// Get all products page by page
var products = module.exports.getProductsByPage()
res.status(200).send(products)
},
getProductsByPage(page = 1, products = []) {
nuvemshop.get(`products?page=${page}&per_page=200`)
.then(res => {
console.log('GET Products PAGE ' + page)
products.push(res.data)
arguments.callee(++page, products)
})
.catch(e => {
if(e.response.status === 404) {
console.log('LAST PAGE REACHED')
return products
} else
return e
})
},
以下是否有效或是否给出 errors/unexpected 结果?
const getProductsByPage = (page = 1, products = []) =>
//you need to return the promise here, arrow without {} block
// returns the single statement (x=>y = function(x){return y;})
nuvemshop.get(`products?page=${page}&per_page=200`)
.then(res => {
console.log('GET Products PAGE ' + page);
//you need to return the promise here
// call recursively
return getProductsByPage(
page+1,
products.concat(res.data)
);
})
.catch(e => {
if (e.response.status === 404) {
console.log('LAST PAGE REACHED')
return products
} else
return e
});
const sync = (req, res) => {
// Get all products page by page
var products = getProductsByPage()
.then(
products=>
res.status(200).send(products)
).catch(
err =>
res.status(500).send(err)
);
};
module.exports = {
sync
}
以下是一次获取 10 页而不是一页一页获取的版本。如果出现问题,它将产生 Fail
类型的结果,并删除 404 响应的 Fail
类型,但将保存任何其他失败原因:
const Fail = function(reason){this.reason = reason;};
const isFail = x=>(x&&x.constructor)===Fail;
const isNotFail = x=>!isFail(x);
const getProductsByPage = (pagesInSet=10) => {
//set up max 3 requests per second
//const max3 = throttlePeriod(3,1000);
const recur = (startAt,products) =>
Promise.all(
Array.from(new Array(pagesInSet),(_,index)=>index+startAt)
.map(
page=>
//for throttled
//max3(nuvemshop.get.bind(nuvemshop))(`products?page=${page}&per_page=200`)
nuvemshop.get(`products?page=${page}&per_page=200`)
.catch(
e=>new Fail(e,page)
)
)
).then(
resultSet=>{
//check if any results came back with 404
const needStop = resultSet
.filter(isFail)
.filter(
fail=>{
const [e] = fail;
return e.response.status === 404;
}
);
if(needStop.length!==0){
const without404 = products.concat(
resultSet.filter(
result=>{
if(isFail(result)){
const [e] = result;
return e.response.status !== 404;
}
return true;
}
)
);
return without404;
}
//get the next pagesInSet pages
return recur(startAt+pagesInSet,products.concat(resultSet));
}
);
return recur(1,[]);
}
const sync = (req, res) => {
// Get all products in sets of 10 parallel requests
var products = getProductsByPage(10)
.then(
products=> {
//you may want to do something with failed request (non 404)
//const failed = products.filter(isFail)
res.status(200).send(products);
}
).catch(
err =>
res.status(500).send(err)
);
};
module.exports = {
sync
}
我需要从 API 端点 (/products) 获取项目列表,但它们是分页的(每页最多 200 个项目)。
我需要创建一个循环来获得 200 个产品,推送到一个数组,并增加页码,这样它就可以请求更多的 200 个产品。当出现404错误(页面不存在)时它会停止,这意味着我得到了所有产品。
我正在使用基于 Promise 的 Axios 来处理请求,但我无法让它工作。我尝试了几种方法,甚至创建了我自己的 Promise,但结果是一样的:
- 无法让它等待所有页面被请求
- 它将始终请求相同的页面,因为页面增量在 .then 的 promise 中(以确保我不会超出最后一页)
我知道 Promises 的想法是异步的,但我正在努力寻找一种方法让它发挥作用。
任何人都知道我可以使用什么逻辑来执行此操作?我只想在继续之前获得所有项目。也许我过于复杂了,一些澄清会很有帮助。
编辑:
尝试递归执行,但执行前结果总是return:
module.exports = {
sync(req, res) {
// Get all products page by page
var products = module.exports.getProductsByPage()
res.status(200).send(products)
},
getProductsByPage(page = 1, products = []) {
nuvemshop.get(`products?page=${page}&per_page=200`)
.then(res => {
console.log('GET Products PAGE ' + page)
products.push(res.data)
arguments.callee(++page, products)
})
.catch(e => {
if(e.response.status === 404) {
console.log('LAST PAGE REACHED')
return products
} else
return e
})
},
以下是否有效或是否给出 errors/unexpected 结果?
const getProductsByPage = (page = 1, products = []) =>
//you need to return the promise here, arrow without {} block
// returns the single statement (x=>y = function(x){return y;})
nuvemshop.get(`products?page=${page}&per_page=200`)
.then(res => {
console.log('GET Products PAGE ' + page);
//you need to return the promise here
// call recursively
return getProductsByPage(
page+1,
products.concat(res.data)
);
})
.catch(e => {
if (e.response.status === 404) {
console.log('LAST PAGE REACHED')
return products
} else
return e
});
const sync = (req, res) => {
// Get all products page by page
var products = getProductsByPage()
.then(
products=>
res.status(200).send(products)
).catch(
err =>
res.status(500).send(err)
);
};
module.exports = {
sync
}
以下是一次获取 10 页而不是一页一页获取的版本。如果出现问题,它将产生 Fail
类型的结果,并删除 404 响应的 Fail
类型,但将保存任何其他失败原因:
const Fail = function(reason){this.reason = reason;};
const isFail = x=>(x&&x.constructor)===Fail;
const isNotFail = x=>!isFail(x);
const getProductsByPage = (pagesInSet=10) => {
//set up max 3 requests per second
//const max3 = throttlePeriod(3,1000);
const recur = (startAt,products) =>
Promise.all(
Array.from(new Array(pagesInSet),(_,index)=>index+startAt)
.map(
page=>
//for throttled
//max3(nuvemshop.get.bind(nuvemshop))(`products?page=${page}&per_page=200`)
nuvemshop.get(`products?page=${page}&per_page=200`)
.catch(
e=>new Fail(e,page)
)
)
).then(
resultSet=>{
//check if any results came back with 404
const needStop = resultSet
.filter(isFail)
.filter(
fail=>{
const [e] = fail;
return e.response.status === 404;
}
);
if(needStop.length!==0){
const without404 = products.concat(
resultSet.filter(
result=>{
if(isFail(result)){
const [e] = result;
return e.response.status !== 404;
}
return true;
}
)
);
return without404;
}
//get the next pagesInSet pages
return recur(startAt+pagesInSet,products.concat(resultSet));
}
);
return recur(1,[]);
}
const sync = (req, res) => {
// Get all products in sets of 10 parallel requests
var products = getProductsByPage(10)
.then(
products=> {
//you may want to do something with failed request (non 404)
//const failed = products.filter(isFail)
res.status(200).send(products);
}
).catch(
err =>
res.status(500).send(err)
);
};
module.exports = {
sync
}