puppeteer爬取数据 await与forEach的问题解决方法

前端之家收集整理的这篇文章主要介绍了puppeteer爬取数据 await与forEach的问题解决方法前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

在使用puppeteer爬取数据时,遇到了个报错问题,才发现了这个forEach与await的问题。

一、问题

利用搜集到的url,再去爬去对应数据时,我采用了forEach循环爬取,去遇到提示如下:UnhandledPromiseRejectionWarning: Error: Navigation Failed because browser has disconnected!,换句话说就是,还没爬,浏览器就关闭了,大概就是异步问题了。

《await与forEach》

简化下问题的过程,先创建个简单的sleep函数假装处理业务逻辑,

  1. async function sleep(time = 1000) {
  2.     return new Promise((resolve) => {
  3.         setTimeout(() => {
  4.             resolve();
  5.         },time);
  6.     });
  7. }

主体函数

  1. (async () => {
  2.     await sleep();
  3.     console.log('start');
  4.  
  5.     [0,1,2].forEach(async () => {
  6.         await sleep();
  7.         console.log(1111);
  8.     });
  9.     console.log('finish');
  10. })();

用node运行下,实际,forEach中的await并没有阻挡 finish 字符的输出,并且forEach创造出来的函数之间也并没有先后关联,三个1111几乎同时输出

二、原因

为什么会造成这种原因呢?

再看下async与await的关系,只有在同一个async函数中,await才会按照对应的执行顺序依次执行,我们都知道forEach创造了独立的async函数(闭包问题),他内部的await已经与最外层的自执行async函数没有关联了(因为forEach并不是async函数),因此,循环出的三个方法也没有关联,都是各自等待1s就输出

三、解决方法

使用for循环

既然这样,我们就是用不新建函数的循环,

  1. for (let i = 0; i < 3; ++i) {
  2.     await sleep();
  3.     console.log(1111);
  4. }

改造forEach

修改原型上的forEach方法,不推荐,你可以新写个each方法

  1. Array.prototype.forEach = async function(fn) {
  2.     let len = this.length;
  3.     for (let i = 0; i < len; ++i) {
  4.         await fn.call(this[i],i);
  5.     }
  6. };

这样就可以了,最后,使用await写异步真是太爽了。

附上demo:await与foreach

猜你在找的Python相关文章