puppeteer: async function inside evaluate fails

Code

await page.evaluate(async () => {
    console.log('1')
})

Error

(node:66796) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Evaluation failed: ReferenceError: fn is not defined
    at <anonymous>:1:26

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 16
  • Comments: 16 (6 by maintainers)

Commits related to this issue

Most upvoted comments

Are you transforming your code with babel? The babel async function code isn’t compatible with Puppeteer. We call function.toString and send your code into Chromium, but babel messes with that and we end up sending an incomplete string. You can get around this by using template strings instead of functions.

await page.evaluate(`(async() => {
   console.log('1');
})()`);

same issue, different error, using TypeScript (not babel). The solution for me was to instruct TypeScript to compile to latest ecma version so no pollyfills / artificial code is generated for async function support, in tsconfig.json file:

{
  "compilerOptions": {
    "target": "es2018"
  }
}

issue details

While the following works OK:

    let result = await page.evaluate( ()=>{
      return Promise.resolve('hello')
    })

the equivalent code using async functions throws the following error:

    let result = await page.evaluate(async ()=>{
      return 'hello'
    })

Error:

  Message:
    Error: Evaluation failed: ReferenceError: __awaiter is not defined
        at __puppeteer_evaluation_script__:1:8
  Stack:
    Error: Evaluation failed: ReferenceError: __awaiter is not defined
        at __puppeteer_evaluation_script__:1:8
        at ExecutionContext.evaluateHandle (/home/sg/git/autumn-leaves/imagemagick-browser/node_modules/puppeteer/lib/ExecutionContext.js:106:13)
        at process._tickCallback (internal/process/next_tick.js:68:7)
        at <Jasmine>
        at ExecutionContext.<anonymous> (/home/sg/git/autumn-leaves/imagemagick-browser/node_modules/puppeteer/lib/helper.js:144:27)
        at ExecutionContext.evaluate (/home/sg/git/autumn-leaves/imagemagick-browser/node_modules/puppeteer/lib/ExecutionContext.js:58:31)
        at ExecutionContext.<anonymous> (/home/sg/git/autumn-leaves/imagemagick-browser/node_modules/puppeteer/lib/helper.js:145:23)
        at Frame.evaluate (

puppeteer v1.0.0-rc ( git://github.com/GoogleChrome/puppeteer.git#fc2fc0d ) centos-release-7-3.1611.el7.centos.x86_64

const puppeteer = require('puppeteer');

(async function main() {
  try {
    const browser = await puppeteer.launch({args: ['--no-sandbox', '--disable-setuid-sandbox']});
    const page = await browser.newPage();

    await page.goto('https://example.org/');

    await page.evaluate(async () => {
      console.log('1');
    });

    await browser.close();
  } catch (err) {
    console.error(err);
  }
})();
Error: Evaluation failed: ReferenceError: fn is not defined
    at <anonymous>:1:26
    at ExecutionContext.evaluateHandle (...node_modules/puppeteer/lib/ExecutionContext.js:70:13)
    at <anonymous>
    at process._tickDomainCallback [as _tickCallback] (internal/process/next_tick.js:228:7)

Are you transforming your code with babel? The babel async function code isn’t compatible with Puppeteer. We call function.toString and send your code into Chromium, but babel messes with that and we end up sending an incomplete string. You can get around this by using template strings instead of functions.

await page.evaluate(`(async() => {
   console.log('1');
})()`);

Hi, I’m trying to use with Echart library to generate and get its based64 image.

    await page.addScriptTag({path: __dirname + '/echarts-all.js'});
    await page.setContent(`
        <html><body>
                <div id="chartdiv"></div>
                <script>
                    var myChart = echarts.init(document.getElementById('chartdiv')); 
                    myChart.setOption(option); 
                </script>
            </body>            
        </html>  
  `);
   const base64img = await page.evaluate(`(async() => { myChart.getDataURL(); })()`);
   console.log('base64img', base64img);

However the base64img is undefined. Is there any solution to make it works perfectly with Babel?

@jtara1: we made our serialization logic more clever so that it doesn’t bite you next time. We’ll update our docs to explain the function serialization.

You can’t import something from Node and use it in Chromium. You have to navigate Chromium to a webpage that includes your utility script.

@reservce - This solution works great! But I agree, it’s obviously not a true solution (after all, a template string is technically just a string, though it will get eval’ed as actual code…)

As a side question: How did you know to do this, or figure out how to do this?

@yujiosaka not sure what would be the good place in the docs. There’s been quite a bit discussion on babel on the bugtracker, so it should be searchable now.

Speculatively closing this since the issue seems to be related to transpilation.