Javascript петли, асин c функции и безголовый браузер - PullRequest
2 голосов
/ 04 февраля 2020

Играя с новым безголовым браузером-драматургом от Microsoft, я создал что-то, что не возвращает ни ошибки, ни чего-то еще.

В настоящее время мои идеи закончились, и я прошу вас дать некоторые подсказки, чтобы указать мне на мою ошибку.

Этот фрагмент кода должен просто запустить асинхронную работу группы безголовых браузеров. Но запуск браузера зависает и приложение остается в бесконечном l oop. Я вставляю код здесь, это простой 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

Ответы [ 3 ]

2 голосов
/ 04 февраля 2020

Есть несколько вещей, которые вы можете улучшить в своем коде:

(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);
  }
})()

Давайте обернем все в асинхронную c функцию

(async()=>{
)();

Тогда давайте посмотрим на эти задачи / обещания:

const promises = [];
...
log('fire async');
promises.push((async () => {
})());

Если вы выходите из рабочих, вам нужно подождать их:

if (running < maxRunners) {
...
} else {
   await Promise.all(promises);
}

Вы должны начать работать с этим.

1 голос
/ 04 февраля 2020

Сразу же вызванные функции выполняются без ожидания окончания sh. Например:

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 , вы должны обернуть весь свой код в asyn c функцию:

(async () => {
   ...all your code
})();
1 голос
/ 04 февраля 2020

Я не верю, что ваша асинхронная c функция действительно оценивается.

Вместо того, чтобы вызывать асинхронную c функцию один раз за итерацию, вы могли бы создать список обещаний и использовать Promise.all ()

...