Javascript 使用循环进行异步和等待
我有一个用JavaScript编写的小代码,可以获取html页面的内容,然后对它们进行处理(爬虫)。 问题是请求导致异步执行。 我尝试使用Promissions和async&await,但在异步执行时仍然遇到同样的问题,原因是我想一次抓取多个页面,以便移动到下一个目标。 这里有一个类似的代码:Javascript 使用循环进行异步和等待,javascript,node.js,Javascript,Node.js,我有一个用JavaScript编写的小代码,可以获取html页面的内容,然后对它们进行处理(爬虫)。 问题是请求导致异步执行。 我尝试使用Promissions和async&await,但在异步执行时仍然遇到同样的问题,原因是我想一次抓取多个页面,以便移动到下一个目标。 这里有一个类似的代码: const rootlink= 'https://jsonplaceholder.typicode.com/posts/'; async function f (){ await f1()
const rootlink= 'https://jsonplaceholder.typicode.com/posts/';
async function f (){
await f1()
f3()
}
async function f1(){
return new Promise(async (resolve,reject)=>{
log('f1 start');
for(let i=1;i<11;i++){
await request(rootlink+i,(err, res,html)=>{
if(!err && res.statusCode==200){
log('link '+i +' done');
resolve();
}
else reject()
})
}
})
}
function f3(){
console.log('f3')
}
f()
constrootlink='1〕https://jsonplaceholder.typicode.com/posts/';
异步函数f(){
等待f1()
f3()
}
异步函数f1(){
返回新承诺(异步(解析、拒绝)=>{
日志(“f1开始”);
for(设i=1;i{
如果(!err&&res.statusCode==200){
日志('link'+i+'done');
解决();
}
否则拒绝()
})
}
})
}
函数f3(){
console.log('f3')
}
f()
结果应该是:
f1起点
链接1完成
链接2完成
链接3完成
链接4完成
链接5完成
链接6完成
链接7完成
链接8完成
链接9完成
链接10完成
f3
而不是
f1起点
链接1完成
f3
链接2完成
链接3完成
链接4完成
链接5完成
链接6完成
链接7完成
链接8完成
链接9完成
link 10 done如果您想并行执行多个非同步操作,您实际上不想等待它们,因为这会阻塞您的功能 首先,我认为最好找到一个使用承诺的HTTP库。您使用的那个有回调,但我相信
request
项目也有一个request-promise
包,它更易于使用
下面是f1函数的固定版本,它可以更正确地使用承诺。注意,这还没有并行化
const request = require('request-promise');
async function f1(){
log('f1 start');
for(let i=1;i<11;i++){
const res = await request(rootlink+i);
if(res.statusCode==200){
log('link '+i +' done');
}
}
}
const request=require('request-promise');
异步函数f1(){
日志(“f1开始”);
对于(设i=1;i我的问题的答案是使用来自的同步请求'sync request'
注意:我会使用一个同构的fetch包来创建可以在多个环境中使用的代码。即使您不打算在浏览器中使用它,熟悉API对将来的使用也是非常有益的。至少,这个想法让我可以编写一个代码片段,您可以在StackOverflow上实际运行
是你的答案不管你使用什么软件包。你只需等待所有承诺都得到解决,然后按照你的逻辑:
//const fetch=require('node-fetch')
常量fetchData=(…args)=>fetch(…args)。然后(r=>{
如果(!r.ok)抛出新错误('Error!')
返回r.json()
})
const getAllPostsAsync=(postIds)=>Promise.all(
map(postId=>fetchData(`https://jsonplaceholder.typicode.com/posts/${postId}`)
)
;(异步()=>{
const posts=await getAllPostsAsync([1,2,3,4,5,6,7,8,9,10])
//TODO:在等待加载所有帖子之后,这里是您的逻辑
控制台日志(posts)
})()
似乎您想要实现的不是真正的异步,您可能希望执行同步请求,而不是执行同步请求是的,这就是我真正想要的返回新承诺(异步(…
有点奇怪。为什么不只返回(异步(…)=>{…})()
。可能实际上不会改变任何东西,但是删除不必要的代码和缩进对调试来说从来都不是坏事。看看这个:谢谢你先生的回答。问题是在我的情况下,我必须在同步操作中这样做,以便稍后将结果存储到文件中。现实我的第二个函数(f2)根据第一个函数(f1)给出的结果进行爬网。然后还有另一个函数在两个预览函数完成其工作时存储结果。此软件包警告“您不应在生产应用程序中使用此功能”。我建议不要将同步请求作为您的解决方案来解决。是的,我看到了这个警告。在我找到更好的解决方案之前,这是我目前唯一的解决方案(我会想出另一种避免同步操作的方法)
async function f1(){
log('f1 start');
const promises = [];
for(let i=1;i<11;i++){
promises.push(
request(rootlink+i).then( (res) => {
if(res.statusCode==200){
log('link '+i +' done');
}
})
);
}
await Promise.all(promises);
}
async function f1(){
log('f1 start');
const promises = [];
for(let i=1;i<11;i++){
promises.push(checkLink(i));
}
await Promise.all(promises);
}
async function checkLink(i) {
const res = await request(rootlink+i);
if (res.statusCode==200){
log('link '+i +' done');
}
}