Javascript 循环、异步函数和无头浏览器
Javascript loops, async functions and headless browser
通过使用来自微软的新无头浏览器 playwriter,我构建了既 returns 错误也不是其他东西的东西。
至此,我的思路已经结束,请大家指点指点我的失败。
这段代码应该只是启动一个多头无头浏览器组异步。
但是浏览器的启动挂起并且应用程序处于无限循环中。
我在这里粘贴代码,它是一个简单的 nodejs 脚本,用于重现该行为。
感谢您的帮助和阅读 ;)
const playwright = require('playwright');
log('start playwright async');
let maxRunners = 1;
let running = 0;
let list = [1,2,3,4,5,6,7,8,9,0,11,12,13,14,15];
log('start job');
while (list.length > 0) {
if (running < maxRunners) {
log('runner started');
running++;
let entry = list[0];
list.shift();
log('start browser loop');
for (const browserType of ['chromium', 'firefox', 'webkit']) {
log('fire async');
(async () => {
log('loop next');
log('launch: ', browserType);
const browser = await playwright[browserType].launch({
headless: false
});
log(browserType, ' launched');
const context = await browser.newContext();
log('open new page');
const page = await context.newPage('http://whatsmyuseragent.org/');
log('page opened');
log('make screenshot');
await page.screenshot({path: `example-${browserType}.png`});
log('screenshot made');
log('close browser');
await browser.close();
log('browser closed');
log('loop succeed');
running--;
})();
log('end async');
}
log('end loop');
if (running === 0 && list.length === 0) {
log('job finished');
}
}
}
log('end playwright script');
function log(...msgs) {
let date = new Date();
let timeString = date.toISOString().substr(11, 8);
let msg = '';
for (let i in msgs) {
msg += msgs[i];
}
console.log(timeString, ':', msg);
}
输出:
20:53:29 : start playwright async
20:53:29 : start job
20:53:29 : runner started
20:53:29 : start browser loop
20:53:29 : fire async
20:53:29 : loop next
20:53:29 : launch: chromium
20:53:29 : end async
20:53:29 : fire async
20:53:29 : loop next
20:53:29 : launch: firefox
20:53:29 : end async
20:53:29 : fire async
20:53:29 : loop next
20:53:29 : launch: webkit
20:53:29 : end async
20:53:29 : end loop
我不相信你的异步函数实际上正在被评估。
您可以创建一个承诺列表并使用 Promise.all(),而不是每次迭代都调用一次异步函数吗?
立即-调用的函数无需等待完成即可执行。例如:
const promise = (time = 1, shouldThrowError = false) => new Promise((resolve, reject) => {
timeInMs = time * 1000
setTimeout(()=>{
console.log(`Waited ${time} secs`)
if (shouldThrowError) reject(new Error('Promise failed'))
resolve(time)
}, timeInMs)
});
// Start excuting first async immediate function
(async () => {
try {
console.log('starting first promise')
await promise(1)
console.log('finished first promise')
} catch (error) {
}
})();
// This executes without finishing previous promise
(async () => {
try {
console.log('starting second promise')
await promise(1)
console.log('finished second promise')
} catch (error) {
}
})();
更改您的块代码:
(async () => {
log('loop next');
...
log('loop succeed');
running--;
})();
至:
const process = async () => {
log('loop next');
...
log('loop succeed');
running--;
};
await process()
此外,为了能够使用 await,您应该将所有代码包装在一个异步函数中:
(async () => {
...all your code
})();
您可以在代码中改进一些地方:
(async()=>{
log('start playwright async');
let maxRunners = 1;
let running = 0;
let list = [1,2,3,4,5,6,7,8,9,0,11,12,13,14,15];
log('start job');
const promises = [];
while (list.length > 0) {
if (running < maxRunners) {
log('runner started');
running++;
let entry = list[0];
list.shift();
log('start browser loop');
for (const browserType of ['chromium', 'firefox', 'webkit']) {
log('fire async');
promises.push((async () => {
log('loop next');
log('launch: ', browserType);
const browser = await playwright[browserType].launch({
headless: false
});
log(browserType, ' launched');
const context = await browser.newContext();
log('open new page');
const page = await context.newPage('http://whatsmyuseragent.org/');
log('page opened');
log('make screenshot');
await page.screenshot({path: `example-${browserType}.png`});
log('screenshot made');
log('close browser');
await browser.close();
log('browser closed');
log('loop succeed');
running--;
})());
log('end async');
}
log('end loop');
} else {
await Promise.all(promises);
}
}
await Promise.all(promises);
log('job finished');
log('end playwright script');
function log(...msgs) {
let date = new Date();
let timeString = date.toISOString().substr(11, 8);
//date.setSeconds(45); // specify value for SECONDS here
//var timeString = date.toISOString().substr(11, 8);
let msg = '';
for (let i in msgs) {
msg += msgs[i];
}
console.log(timeString, ':', msg);
}
})()
让我们将所有内容包装在一个异步函数中
(async()=>{
)();
然后,让我们跟踪那些 tasks/promises:
const promises = [];
...
log('fire async');
promises.push((async () => {
})());
如果你离开了工人,你需要等待他们:
if (running < maxRunners) {
...
} else {
await Promise.all(promises);
}
你应该 运行 这个。
根据@hardkoded 的出色回答在同一行:
简而言之,使用带有承诺的异步函数:
一个简单的例子来说明同一点:
function delay() {
return new Promise(resolve => setTimeout(resolve, 300));
}
async function delayedLog(item) {
// notice that we can await a function
// that returns a promise
await delay();
console.log(item);
}
async function processArray(array) {
// map array to promises
const promises = array.map(delayedLog);
// wait until all promises are resolved
await Promise.all(promises);
console.log('Done!');
}
尝试一下,用它来了解 javaScript!
中的异步行为
通过使用来自微软的新无头浏览器 playwriter,我构建了既 returns 错误也不是其他东西的东西。
至此,我的思路已经结束,请大家指点指点我的失败。
这段代码应该只是启动一个多头无头浏览器组异步。 但是浏览器的启动挂起并且应用程序处于无限循环中。 我在这里粘贴代码,它是一个简单的 nodejs 脚本,用于重现该行为。
感谢您的帮助和阅读 ;)
const playwright = require('playwright');
log('start playwright async');
let maxRunners = 1;
let running = 0;
let list = [1,2,3,4,5,6,7,8,9,0,11,12,13,14,15];
log('start job');
while (list.length > 0) {
if (running < maxRunners) {
log('runner started');
running++;
let entry = list[0];
list.shift();
log('start browser loop');
for (const browserType of ['chromium', 'firefox', 'webkit']) {
log('fire async');
(async () => {
log('loop next');
log('launch: ', browserType);
const browser = await playwright[browserType].launch({
headless: false
});
log(browserType, ' launched');
const context = await browser.newContext();
log('open new page');
const page = await context.newPage('http://whatsmyuseragent.org/');
log('page opened');
log('make screenshot');
await page.screenshot({path: `example-${browserType}.png`});
log('screenshot made');
log('close browser');
await browser.close();
log('browser closed');
log('loop succeed');
running--;
})();
log('end async');
}
log('end loop');
if (running === 0 && list.length === 0) {
log('job finished');
}
}
}
log('end playwright script');
function log(...msgs) {
let date = new Date();
let timeString = date.toISOString().substr(11, 8);
let msg = '';
for (let i in msgs) {
msg += msgs[i];
}
console.log(timeString, ':', msg);
}
输出:
20:53:29 : start playwright async
20:53:29 : start job
20:53:29 : runner started
20:53:29 : start browser loop
20:53:29 : fire async
20:53:29 : loop next
20:53:29 : launch: chromium
20:53:29 : end async
20:53:29 : fire async
20:53:29 : loop next
20:53:29 : launch: firefox
20:53:29 : end async
20:53:29 : fire async
20:53:29 : loop next
20:53:29 : launch: webkit
20:53:29 : end async
20:53:29 : end loop
我不相信你的异步函数实际上正在被评估。
您可以创建一个承诺列表并使用 Promise.all(),而不是每次迭代都调用一次异步函数吗?
立即-调用的函数无需等待完成即可执行。例如:
const promise = (time = 1, shouldThrowError = false) => new Promise((resolve, reject) => {
timeInMs = time * 1000
setTimeout(()=>{
console.log(`Waited ${time} secs`)
if (shouldThrowError) reject(new Error('Promise failed'))
resolve(time)
}, timeInMs)
});
// Start excuting first async immediate function
(async () => {
try {
console.log('starting first promise')
await promise(1)
console.log('finished first promise')
} catch (error) {
}
})();
// This executes without finishing previous promise
(async () => {
try {
console.log('starting second promise')
await promise(1)
console.log('finished second promise')
} catch (error) {
}
})();
更改您的块代码:
(async () => {
log('loop next');
...
log('loop succeed');
running--;
})();
至:
const process = async () => {
log('loop next');
...
log('loop succeed');
running--;
};
await process()
此外,为了能够使用 await,您应该将所有代码包装在一个异步函数中:
(async () => {
...all your code
})();
您可以在代码中改进一些地方:
(async()=>{
log('start playwright async');
let maxRunners = 1;
let running = 0;
let list = [1,2,3,4,5,6,7,8,9,0,11,12,13,14,15];
log('start job');
const promises = [];
while (list.length > 0) {
if (running < maxRunners) {
log('runner started');
running++;
let entry = list[0];
list.shift();
log('start browser loop');
for (const browserType of ['chromium', 'firefox', 'webkit']) {
log('fire async');
promises.push((async () => {
log('loop next');
log('launch: ', browserType);
const browser = await playwright[browserType].launch({
headless: false
});
log(browserType, ' launched');
const context = await browser.newContext();
log('open new page');
const page = await context.newPage('http://whatsmyuseragent.org/');
log('page opened');
log('make screenshot');
await page.screenshot({path: `example-${browserType}.png`});
log('screenshot made');
log('close browser');
await browser.close();
log('browser closed');
log('loop succeed');
running--;
})());
log('end async');
}
log('end loop');
} else {
await Promise.all(promises);
}
}
await Promise.all(promises);
log('job finished');
log('end playwright script');
function log(...msgs) {
let date = new Date();
let timeString = date.toISOString().substr(11, 8);
//date.setSeconds(45); // specify value for SECONDS here
//var timeString = date.toISOString().substr(11, 8);
let msg = '';
for (let i in msgs) {
msg += msgs[i];
}
console.log(timeString, ':', msg);
}
})()
让我们将所有内容包装在一个异步函数中
(async()=>{
)();
然后,让我们跟踪那些 tasks/promises:
const promises = [];
...
log('fire async');
promises.push((async () => {
})());
如果你离开了工人,你需要等待他们:
if (running < maxRunners) {
...
} else {
await Promise.all(promises);
}
你应该 运行 这个。
根据@hardkoded 的出色回答在同一行:
简而言之,使用带有承诺的异步函数:
一个简单的例子来说明同一点:
function delay() {
return new Promise(resolve => setTimeout(resolve, 300));
}
async function delayedLog(item) {
// notice that we can await a function
// that returns a promise
await delay();
console.log(item);
}
async function processArray(array) {
// map array to promises
const promises = array.map(delayedLog);
// wait until all promises are resolved
await Promise.all(promises);
console.log('Done!');
}
尝试一下,用它来了解 javaScript!
中的异步行为