Search code examples
javascriptfunctional-programmingasync-awaitecmascript-2016

From single argument function application to a mapping over an array using async/await in node


I'm new to await/async in modern javascript. I understand there are a lot of questions related to this in general, but in this question, I'm looking specifically for a template for thinking through how to take a single function and rewrite it as a map over an array.

I'm starting with a very simple screenshot function from here:

const puppeteer = require('puppeteer');

puppeteer.launch().then(async browser => {
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await page.screenshot({path: 'screenshot.png'});
  await browser.close();
});

This just does one screenshot. I'd like to give it an array, and have it take multiple screenshots.

For my application, I tweak this slightly with the mypage variable:

const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser => {
  const mypage = 1
  const page = await browser.newPage();
  await page.goto(`https://localhost:9001/${mypage}`);
  await page.screenshot({path: `${mypage}.png`});
  await browser.close();
});

Now, I'd like to parameterize this list over mypages = [1 ... 1000]. In older javascript, using underscore.js, I'd try something like:

// define the function
function ss(mypage) {
  puppeteer.launch().then(async browser => {
    const page = await browser.newPage();
    await page.goto(`https://localhost:9001/${mypage}`);
    await page.screenshot({path: `${mypage}.png`});
    await browser.close();
});  
}

// populate the array of pages, eg make var mypages = [1,2,3...1000]
var mypages = [];
for (var i = 1; i <= 1000; i++) {
    mypages.push(i);
}

// call the screenshot function on each page in my pages.
_.each(mypages, ss)

It is not clear to me how I could use async/await to work over each page in mypages (and potentially to generate this array more idiomatically, too).

How can I rewrite my puppeteer function which works for mypage = 1, to map over the whole array of mypages?


Solution

  • The screenshot function should be async:

     async function screenshot(mypage) {
      const browser = await  puppeteer.launch();
      const page = await browser.newPage();
      await page.goto(`https://localhost:9001/${mypage}`);
      await page.screenshot({path: `${mypage}.png`});
      await browser.close();
    }
    

    Then do one screenshot after another:

     (async function() {
        for(let i = 0; i < 1000; i++)
          await screenshot(i);
     })();
    

    Or all at the same time (not sure if that works):

     Promise.all(Array.from({ length: 1000 }, (_, i) => screenshot(i)))
      .then(/*...*/);