puppeteer爬取資料 await與forEach的問題解決方法
阿新 • • 發佈:2020-12-18
原文:https://www.jb51.cc/python/454296.html
在使用puppeteer爬取資料時,遇到了個報錯問題,才發現了這個forEach與await的問題。
一、問題
利用搜集到的url,再去爬去對應資料時,我採用了forEach迴圈爬取,去遇到提示如下:UnhandledPromiseRejectionWarning: Error: Navigation failed because browser has disconnected!,換句話說就是,還沒爬,瀏覽器就關閉了,大概就是非同步問題了。
簡化下問題的過程,先建立個簡單的sleep函式假裝處理業務邏輯,
async function sleep(time = 1000) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
},time);
});
}
主體函式:
(async () => { await sleep(); console.log('start'); [0,1,2].forEach(async () => { await sleep(); console.log(1111); }); console.log('finish'); })();
用node執行下,實際,forEach中的await並沒有阻擋 finish 字元的輸出,並且forEach創造出來的函式之間也並沒有先後關聯,三個1111幾乎同時輸出。
二、原因
為什麼會造成這種原因呢?
再看下async與await的關係,只有在同一個async函式中,await才會按照對應的執行順序依次執行,我們都知道forEach創造了獨立的async函式(閉包問題),他內部的await已經與最外層的自執行async函式沒有關聯了(因為forEach並不是async函式),因此,迴圈出的三個方法也沒有關聯,都是各自等待1s就輸出。
三、解決方法
使用for迴圈
既然這樣,我們就是用不新建函式的迴圈,
for (let i = 0; i < 3; ++i) {
await sleep();
console.log(1111);
}
改造forEach
修改原型上的forEach方法,不推薦,你可以新寫個each方法,
Array.prototype.forEach = async function(fn) {
let len = this.length;
for (let i = 0; i < len; ++i) {
await fn.call(this[i],i);
}
};
這樣就可以了,最後,使用await寫非同步真是太爽了。
附上demo:await與foreach。