Nodejs forEach 中调用 promise 如何控制执行顺序?
Nodejs forEach 中调用 promise 如何控制执行顺序?
最近在做一个网页爬虫,先抓取列表页面,再获取列表页所有内容页的 url,然后将所有列表页的 url 循环调用抓取方法,这样导致抓取的顺序不可控,想知道如何能够控制抓取的顺序。 例如:正在抓取 A 页面, A 页面抓取完毕;正在抓取 B 页面, B 页面抓取完毕…按这样的顺序执行。
抓取函数:
function doRequest (url) {
console.log(chalk.red(`正在抓取 ${url} 的内容...`));
return new Promise ((resolve, reject) => {
request
.post(url)
.set(headers)
.charset('utf-8')
.then(result => {
resolve(result.text);
console.log(chalk.red(`${url} 的内容抓取完毕!`));
})
.catch(err => {
reject(err);
})
});
}
调用
// 请求列表
doRequest('list.html')
.then(content => {
return this.parseList(content); // 得到所有的内容页面地址
})
// 请求内容页
.then(links => {
return Promise.all(links.map(link => {
return doRequest(link);
}))
})
.then (allContent => {
console.log(allContent);
})
执行的结果
这个结果不是按照顺序来的。
用 async 模块串行执行吧: https://github.com/caolan/async
array.reduce
Bluebird 的 Promise.each
或者手动拼接 then
links.reduce( (promise, link) => { return promise.then( ()=>{
// do request with link
}) }, Promise.resolve()).then( () =>{
// done
})
这个也只是将所有的请求结果一次性范围。并没有保证顺序~
等待上一个执行完成,再执行下一个。await 了解一下?话说回来,你为啥要顺序执行?
1 楼都已经回答你喽
确定是保证顺序的
加个字段来排序不是更好?页面多了你也一个一个爬啊?
bluebird +1
没人说正经的 for of ???
async + for of 完美解决,反正后端 node 不像前端不能控制版本
all 中,你给的数组的顺序是什么,最终结果就是什么顺序,但是不保证拿到结果的过程的顺序。
大佬,有 demo 么~
(async function() {
// 请求列表
comst links = await doRequest(‘list.html’).then(content => {
return this.parseList(content); // 得到所有的内容页面地址
});
for (const link of links) {
// 请求内容页
const allContent = await doRequest(link);
console.log(allContent);
}
})()
厉害!!!这样可以实现,顺便有个疑问想请教一下
doRequest(‘list.html’).then(content => {
return parseList(content);
}).then(links => {
links.forEach(async function(link){
const allContent = await doRequest(link);
});
})
这样为啥就不行呢~
明白了。。。需要这样写
doRequest(‘list.html’).then(content => {
return parseList(content);
}).then(async function(links){
for (const link of links) {
const allContent = await doRequest(link);
}
})
感谢各位的帮助,谢谢大家。
基于 express/koa 的话为什么不用中间件?
同 #11,使用 for-of 循环解决
Bluebird.mapSeries(…)
Bluebird.map(…, { concurrency: 5 })
在 Node.js 中使用 forEach
循环处理包含 Promise 的异步操作时,由于 forEach
本身不支持异步等待,直接在其中调用 Promise 并不能保证执行顺序。为了确保顺序执行,你可以使用 for...of
循环结合 async/await
。
以下是一个示例代码,展示了如何在 for...of
循环中使用 async/await
来确保 Promise 的顺序执行:
const asyncTasks = [
() => new Promise((resolve) => setTimeout(() => resolve('Task 1'), 1000)),
() => new Promise((resolve) => setTimeout(() => resolve('Task 2'), 500)),
() => new Promise((resolve) => setTimeout(() => resolve('Task 3'), 1500))
];
async function executeTasksInOrder() {
for (const task of asyncTasks) {
const result = await task();
console.log(result);
}
}
executeTasksInOrder().then(() => {
console.log('All tasks completed in order.');
});
在这个例子中,asyncTasks
是一个包含多个返回 Promise 的函数的数组。executeTasksInOrder
是一个异步函数,使用 for...of
循环遍历 asyncTasks
数组,并在每次迭代中使用 await
来等待 Promise 解决。这确保了任务按顺序执行,并且每个任务的结果在控制台上按顺序打印。
使用 for...of
和 async/await
是处理需要顺序执行的异步任务的一种清晰且简洁的方法。