循环和嵌套 Promise
Looping & Nesting Promises
我正在使用 Request-Promise and cheerio 来抓取一些网站数据,基本上我正在尝试实现以下目标:
- 创建一个空数组
- 登录
- 从一个页面获取一些信息并将对象推入数组
- 从另一个页面获取一些信息并将对象推入数组
- 对于数组中的每个 now 对象,我需要:
- 转到存储在该对象中的 URL {link:"some url",项目:[]}
- 遍历在 link 中找到的所有项目,并将其推送到迭代对象中的项目数组,如下所示:{link: "some url" , 项目: [{item},{item}]}.
- 访问完成的orderArray,它应该吐出这样的东西:
{link: "some url", items: [{item},{item}]},
{link: "some url", items: [{item},{item}]},
{link: "some url", items: [{item},{item}]}
第 6 步 是我 运行 遇到问题的地方,如果不按照我的要求将 promise 嵌套在 for 循环中,我不知道该怎么做下面的代码开始变得令人讨厌。我可以在这里指出正确的方向吗?
这是我当前的代码:
let orderArray = [];
rp.post(login)
.then(function(res1){
// Login & Set Cookies
cookieJar = res1.headers['set-cookie'];
return rp(getOpenOrders);
})
.then(function($){
// Get Some Info from getOpenOrders
orderArray.push({info});
return rp(getShippedOrders);
})
.then(function($){
// Get Some Info from getShippedOrders
orderArray.push({info});
return orderArray;
})
.then(function($){
// Loop through each object in the orderArray
for (i = 0,; i < orderArray.length; i++){
rp(orderArray[I].link)
.then(function($){
//Get length of items on page
let itemsOnPage = $('tbody tr').length;
//Get some more details for each object
for (j = 0,; j < items.length; j++) {
let moreinfo = {…};
orderArray.items.push(moreinfo);
}
}
}
return orderArray;
})
.then(function($){
// Log finished Array
console.log(orderArray);
})
.catch(function(err){
console.log(err);
})
};
最简单、最干净的方法是使用 async/await
。该代码不会 运行 并行(除非我们等待 Promise.all
)
.then(async() => {
// Loop through each object in the orderArray
for(let i = 0; i < orderArray.length; i++) {
// Some may argue no await inside loop...
// We wait for rp to resolve, it looks like
// synchronous code so it's easy to understand
const $ = await rp(orderArray[i].link);
let items = $('tbody tr');
for(const item of items) {
let moreinfo = {};
orderArray[i].items.push(moreinfo);
}
}
return orderArray;
})
您还可以使用 Promise.all 并行发送所有请求,并在所有请求完成后处理结果。
.then(() => {
// Loop through each object in the orderArray
const requests = [];
for(const order of orderArray) {
// Push each promise
requests.push(
rp(order.link)
);
}
// This will resolve when every request finishes
// If one fails, it will reject, going to `.catch`
return Promise.all(requests);
})
.then(results => {
// Results is an array containing each individual request result.
results.forEach(($, i) => {
//Get length of items on page
let items = $('tbody tr');
//Get some more details for each object
for(const item of items) {
let moreinfo = {};
orderArray[i].items.push(moreinfo);
}
})
return orderArray;
});
我假设 rp
解析了一个 cheerio 对象,如果没有解析请告诉我。
我无法测试它,因为我没有你的完整代码,但它应该可以工作。
我正在使用 Request-Promise and cheerio 来抓取一些网站数据,基本上我正在尝试实现以下目标:
- 创建一个空数组
- 登录
- 从一个页面获取一些信息并将对象推入数组
- 从另一个页面获取一些信息并将对象推入数组
- 对于数组中的每个 now 对象,我需要:
- 转到存储在该对象中的 URL {link:"some url",项目:[]}
- 遍历在 link 中找到的所有项目,并将其推送到迭代对象中的项目数组,如下所示:{link: "some url" , 项目: [{item},{item}]}.
- 访问完成的orderArray,它应该吐出这样的东西:
{link: "some url", items: [{item},{item}]}, {link: "some url", items: [{item},{item}]}, {link: "some url", items: [{item},{item}]}
第 6 步 是我 运行 遇到问题的地方,如果不按照我的要求将 promise 嵌套在 for 循环中,我不知道该怎么做下面的代码开始变得令人讨厌。我可以在这里指出正确的方向吗?
这是我当前的代码:
let orderArray = []; rp.post(login) .then(function(res1){ // Login & Set Cookies cookieJar = res1.headers['set-cookie']; return rp(getOpenOrders); }) .then(function($){ // Get Some Info from getOpenOrders orderArray.push({info}); return rp(getShippedOrders); }) .then(function($){ // Get Some Info from getShippedOrders orderArray.push({info}); return orderArray; }) .then(function($){ // Loop through each object in the orderArray for (i = 0,; i < orderArray.length; i++){ rp(orderArray[I].link) .then(function($){ //Get length of items on page let itemsOnPage = $('tbody tr').length; //Get some more details for each object for (j = 0,; j < items.length; j++) { let moreinfo = {…}; orderArray.items.push(moreinfo); } } } return orderArray; }) .then(function($){ // Log finished Array console.log(orderArray); }) .catch(function(err){ console.log(err); }) };
最简单、最干净的方法是使用 async/await
。该代码不会 运行 并行(除非我们等待 Promise.all
)
.then(async() => {
// Loop through each object in the orderArray
for(let i = 0; i < orderArray.length; i++) {
// Some may argue no await inside loop...
// We wait for rp to resolve, it looks like
// synchronous code so it's easy to understand
const $ = await rp(orderArray[i].link);
let items = $('tbody tr');
for(const item of items) {
let moreinfo = {};
orderArray[i].items.push(moreinfo);
}
}
return orderArray;
})
您还可以使用 Promise.all 并行发送所有请求,并在所有请求完成后处理结果。
.then(() => {
// Loop through each object in the orderArray
const requests = [];
for(const order of orderArray) {
// Push each promise
requests.push(
rp(order.link)
);
}
// This will resolve when every request finishes
// If one fails, it will reject, going to `.catch`
return Promise.all(requests);
})
.then(results => {
// Results is an array containing each individual request result.
results.forEach(($, i) => {
//Get length of items on page
let items = $('tbody tr');
//Get some more details for each object
for(const item of items) {
let moreinfo = {};
orderArray[i].items.push(moreinfo);
}
})
return orderArray;
});
我假设 rp
解析了一个 cheerio 对象,如果没有解析请告诉我。
我无法测试它,因为我没有你的完整代码,但它应该可以工作。