我正在使用 request-promise npm 包在 nodeJS 中进行多个 api 调用。为了让我获得所需的数据,我必须循环遍历所有类别,然后在每个类别中循环遍历产品数组以获取产品信息。类别响应示例如下
{
"success": true,
"response": [
{
"category_id": 9,
"name": "Leather Wheeled luggage",
"products": [
"TL141911",
"TL141888"
],
"parent_category_id": 34
},
{
"category_id": 10,
"name": "Leather Luggage Weekender Duffles bags",
"products": [
"TL141794",
"TL141658"
],
"parent_category_id": 34
}
}
因为我必须循环并进行 api 调用,所以我尝试使用 Promise.all,但它没有产生正确的结果,它向我抛出 404 未找到错误,有人可以帮助我吗?这里出问题了吗?以下是我尝试过的
const rp = require('request-promise');
const requestUrl = "https://stage.tuscanyleather.it/api/v1/";
const categoryRequestUrl = requestUrl + 'categories';
let tuscanApiOptions = {
uri: categoryRequestUrl,
headers: {
'Authorization': 'Bearer asd343'
},
method: 'Get',
json: true
};
rp(tuscanApiOptions)
.then((categResponse) => {
//res.end(categResponse);
let ps = [];
categResponse.response.forEach((category) => {
if (category.products !== undefined) {
category.products.forEach((product) =>{
let productApiOptions = {
uri: requestUrl + `product-info?code=${product}`,
headers: {
'Authorization': 'Bearer asd343'
},
method: 'Get',
json: true
};
ps.push(rp(productApiOptions));
});
Promise.all(ps)
.then((values) => {
console.log(values); //This is where things are going wrong
})
.catch((err) =>{
console.log(JSON.stringify(err,null,2));
})
}
})
})
.catch((error) => {
console.log(error);
//res.status(error.statusCode).send(error.error.error_description);
});
最佳答案
此代码应该可以帮助您调试 404:
const rp = require('request-promise');
const requestUrl = "https://stage.tuscanyleather.it/api/v1/";
const categoryRequestUrl = `${requestUrl}categories`;
const tuscanApiOptions = {
uri: categoryRequestUrl,
headers: {
'Authorization': 'Bearer asd343'
},
method: 'Get',
json: true
};
// Promise of flat array of products (loses category data)
const productsP = rp(tuscanApiOptions))
.then(({response}) => response
.map(category => category.products) // array of arrays
.flat() // flatten to array of products
.filter(p => !!p) // remove empty
)
const prodUrl = `${requestUrl}product-info?code=`
const productDataP = productsP.then(products =>
products.map(product =>
rp({
...tuscanApiOptions,
uri: `${prodUrl}${product}`
}).catch(e => `Error fetching ${prodUrl}${product} ${e.message}`)
)
)
// Wait for all requests to resolve with data or error.
// resultsP is an array of Promise<productdata|error>
const resultsP = Promise.all(productsDataP)
resultsP.then(console.log)
一些建议,要么接受,要么放弃:
将Array.forEach
从你的编程词汇中剔除。它会给你带来比它解决的问题更多的问题,因为它是副作用的(本质上是一个循环)。使用 Array.map 返回一个新数组,然后对其进行操作。 Array.map
将状态机与数据转换分开,forEach
将它们混合在一起。
不要将 let
或 var
用于不会发生变化的事物。这告诉其他程序员和机器不要依赖该值。使用const
。
参见this article以获得更深入的解释。
使用async
/await
可能更容易做到这一点,至少调试起来是这样。您需要处理数据结构遍历和异步 monad(Promise),以及需要调试的 404。 await
promise 将值扩展到 monad 上下文之外,因此消除了一层复杂性。
当您有 Promise 数组时,您等待 Promise.all(arrayP)
来获取未包装值的数组。
const rp = require('request-promise');
const requestUrl = "https://stage.tuscanyleather.it/api/v1/";
const categoryRequestUrl = `${requestUrl}categories`;
const tuscanApiOptions = {
uri: categoryRequestUrl,
headers: {
'Authorization': 'Bearer asd343'
},
method: 'Get',
json: true
};
async function main() {
const categories = await rp(tuscanApiOptions)
const products = categories.response
.map(category => category.products)
.flat()
.filter(p => !!p) // remove undefined
console.log(products) // should be flat array of products
const prodUrl = `${requestUrl}product-info?code=`
const requestsP = products
.map(product =>
rp({
...tuscanApiOptions,
uri: `${prodUrl}${product}`
}).catch(e => `Error fetching ${prodUrl}${product} ${e.message}`)
)
const results = await Promise.all(requestsP)
console.log(results)
}
main()
关于javascript - 使用promise.all在node js中进行外部api调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60359096/