也许我很困,但是在什么情况下会发生以下情况?
let foo;
page
.evaluate(() => {
// return works... but not closure assignment
// doesn't work
foo = 'foo';
// works
return 'bar';
})
.then(bar => {
console.log('foobar', foo, bar);
// > foobar undefined bar
});
这是在使用木偶戏的摩卡测试中发生的
更新:完整的完整代码
节点9.11.2
/* global describe, it, before, after */
const fs = require('fs-extra');
const path = require('path');
const assert = require('assert');
const puppeteer = require('puppeteer');
const sleep = require('shleep');
const extPath = path.resolve(__dirname, '..', 'build');
const { name } = fs.readJSONSync(path.resolve(extPath, 'manifest.json'));
// Access chrome object in Extensions
// https://github.com/GoogleChrome/puppeteer/issues/2878
describe('chrome extension', () => {
let browser;
let extensionPage;
before(async function() {
this.timeout(90 * 1000);
// start puppeteer
browser = await puppeteer.launch({
headless: false,
args: [
`--disable-extensions-except=${extPath}`,
`--load-extension=${extPath}`
]
});
// poll instead of hope this is enough time?
const EXT_LOAD_DELAY = 100;
await sleep(EXT_LOAD_DELAY);
const targets = await browser.targets();
const extensionTarget = targets.find(
({ _targetInfo }) =>
_targetInfo.type === 'background_page' && _targetInfo.title === name
);
const page = await extensionTarget.page();
let foo;
page
.evaluate(() => {
// return works... but not closure assignment
// doesn't work
foo = 'foo';
// doesn't log
console.log('foo', foo);
// works
return 'bar';
})
.then(bar => {
console.log('foobar', foo, bar);
// > foobar undefined bar
});
});
it('should load', async () => {
assert(true);
});
});
测试屏幕截图
答案 0 :(得分:4)
puppeteer中的evaluate
方法没有在本地或全局代码中声明的变量的概念。传递给evaluate
方法的函数是要在页面上下文(即,在浏览器中)执行的函数。由于foo
没有在页面上下文中声明,因此它无法访问它,因此无法更新其值。
所以逐步浏览代码:
let foo;
await page.evaluate(() => {
foo = 'foo'; // Since no variable foo is known to the evaluate method in the context of your page
// this line , effectively, assigns a new variable called foo with a value 'foo' which
// is then lost once the method has completed since its value is never returned.
return 'bar'; // This value is returned from the method and is therefore retained below
})
.then(bar => {
console.log('foobar', foo, bar);
// foobar is output as expected since you've hardcoded it
// foo is now referring to the global foo you declared earlier but since you have used `let` and not
// assigned it any value, it is output as 'undefined'
// bar is the value you returned from your 'evaluate' function and is therefore output as 'bar' as
// expected in the console log.
});
如果您想使用evaluate
更新变量foo
,则必须这样做:
let foo;
foo = await page.evaluate(() => {
return 'foo'
});
console.log(foo); // Now outputs 'foo' as expected
但是,您可以将变量注入evaluate
方法中并更新它们的值(如果需要),例如:
let foo = 'foo'
console.log(foo); // Outputs 'foo' as expected
foo = await page.evaluate((injectedFoo) => {
return `new${injectedFoo}`;
}, foo);
console.log(foo); // Outputs 'newfoo'
因此,这里发生的是您通过将变量foo
作为参数传递给方法声明的末尾,将变量evaluate
注入了evaluate
方法中。 injectedFoo
方法现在包含一个变量(为清楚起见,我将其称为foo
),该变量带有new
变量的原始值。
然后,我将附加在字符串foo
开头的字符串evaluate
返回到变量字符串,并在控制台中输出该字符串的最终值。
我希望这有助于解释 --env , -e Set environment variables
--env-file You can pass environment variables to your containers with the -e flag.
方法的工作原理!