return 在 Puppeteer/Node.js 中对变量声明语句 (return a = 2;) 的混淆
Confusion around returning a variable declaration statement (return a = 2;) in Puppeteer/Node.js
我正在尝试学习 Node.js 和一些 await/promise,我遇到了这个例子 (https://remarkablemark.org/blog/2018/04/15/puppeteer-without-async-await/):
const puppeteer = require('puppeteer');
let _browser;
let _page;
puppeteer
.launch()
.then(browser => (_browser = browser))
.then(browser => (_page = browser.newPage()))
.then(page => page.goto('https://example.com'))
.then(() => _page)
.then(page => page.screenshot({ path: 'example.png' }))
.then(() => _browser.close());
我理解 .then(browser => (_browser = browser))
与 .then(function(browser) { return _browser = browser; })
相同,但我有点困惑为什么有些行使用 _browser
而有些行使用 browser
(与_page
).
我也不知道 .then(() => _page)
行是干什么用的。为什么这一行没有一个参数,它是前一个函数返回的参数,即 page.goto(...)
?我可能不太了解 Puppeteer 的 .then()
。
我正在尝试清理这段代码并使用 promises 和箭头函数:
puppeteer
.launch()
.then(function(browser) {
return browser.newPage();
})
.then(function(page) {
return page.goto(url).then(function() {
return page.content();
});
})
.then(function(html) {
// do something
})
.catch(function(err) {
//handle error
});
请注意以下事项:
var a; var b = a = 2;
。这将相同的值分配给变量 a
和 b
,因为 a = 2
将值 2
分配给变量 a
和 returns 分配的值是 2
然后分配给变量 b
.
(params?) => returnvalue
或 (params?) => { return returnvalue; }
或 function(params?) { return returnvalue; }
将是相同的函数定义。然而,编译器在几种情况下识别这些函数定义中的 this
关键字的方式发生了一些变化,在这种情况下这不是一个需要关注的问题。
Promise.then
return再次承诺 return Promise
or value
or default undefined
.
解释:
let _browser;
let _page;
puppeteer
.launch()
.then(browser => (_browser = browser))
.then(browser => (_page = browser.newPage()))
.then(page => page.goto('https://example.com'))
// >>> Above .then may not be returning a page, so below .then will replace it with globally referenced _page
.then(() => _page)
.then(page => page.screenshot({ path: 'example.png' }))
// >>> Need a browser reference to close here
.then(() => _browser.close());
为了在整个承诺链中跟踪所需的 browser
或 page
引用,开发人员已在全局变量中分配引用并在整个过程中使用它们。
下面是建议的方法,以便在整个承诺链中清理和维护 [browser, page]
的引用。
puppeteer
.launch()
.then(browser => browser.newPage().then(page => [browser, page]))
.then(([browser, page]) => page.goto('https://example.com').then(() => [browser, page]))
.then(([browser, page]) => page.screenshot({ path: 'example.png' }).then(() => [browser, page]))
.then(([browser, page]) => browser.close());
如果您使用 async
和 await
,代码会显得更清晰。
puppeteer.launch()
returns 以 browser
解析的承诺,可在 then
,
_browser
是局部变量,它将 browser
赋值给它,因为在随后的所有 .then
中携带 browser
会很麻烦,例如, 你在最后看到的_browser.close()
假设用browser.close()
关闭原来的browser
,但是browser
不可用,这就是为什么你需要将它存储在变量中所以你可以做到 _browser.close()
与 _page
和 page
相同的故事
这是使用 async/await
的相同行为:
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
page.screenshot({ path: 'example.png' })
await browser.close()
})()
当谈到 .then(() => _page)
时,其目的是使 page
在下一个 .then
中可用,请参阅下面的代码段,其中 5
返回并可用下一个 .then
const wait = (time) => new Promise((res, rej) => setTimeout(() => res("hello"), time));
let _someVar;
wait(1000)
.then(msg => (_someVar = msg)) // this is .then(_browser => (_browser = browser))
.then(() => 5) // this is .then(() => _page)
.then(x => console.log(x));
console.log("a : ", _someVar);
setTimeout(() => {
console.log("b : ", _someVar);
}, 2000);
那是因为 page.goto() returns :
Promise which resolves to the main resource
response. In case of multiple redirects, the navigation will resolve
with the response of the last redirect.
() => _page
如果 page.goto
返回 page
则不需要
() => _page
,尽管我认为它可以省略并在下一个 _page.screenshot()
中执行 .then
当您为变量赋值时,该赋值的 return 值就是被赋值的值。例如:
let x;
const two = (x = 2); // x = 2 returns '2'
console.log(two); // 2 (return value of x = 2)
console.log(x); // 2 (x is set above to equal 2)
接下来,Promises 和 .then()
有一些需要注意的重要事项:
首先,.then()
将 return 一个可以解析为值的新 Promise。 Promise 解析到的值可以使用 .then(resolvedValue => ...)
.
获得
如前所述,.then()
return是一个可以解析为值的 Promise。 Promise 解析到的值由您传递给 .then()
函数 return 的函数决定。例如,如果您有 .then(() => xyz)
,那么此 .then()
方法调用的 Promise return 将是 Promise<xyz>
。这是说明上面第 1 点和第 2 点的示例:
const promise = Promise.resolve(); // Promise<> (a promise that resolves to the value of undefined/nothing)
const promiseAbc = promise.then(() => 'abc'); // returns Promise<'abc'> (a Promise that resolves to 'abc')
promiseAbc.then(abc => console.log(abc)); // "extract" the resolved value from promiseAbc) (logs: 'abc')
- 如第 2 点所述,回调到
.then()
的 returned 值被 .then()
用作 Promise returned 的解析值称呼。但是,当您 return 来自 .then()
回调的 Promise 时,这会略有不同。 return 不是 return 解析为 Promise 的新 Promise,.then()
方法 return 是您从 .then()
回调中 return 编辑的 Promise。这是一个清除此问题的示例:
const promise = Promise.resolve(); // Promise<> (a promise that resolves to the value of undefined/nothing)
const promiseAbc = Promise.resolve('abc'); // Promise<'abc'> (a promise that resolves to the value of 'abc')
const newPromise = promise.then(() => promiseAbc);
// You might expect that the above would return and set `newPromise` to be:
// Promise<Promise<'abc'>>
// But, as `promiseAbc` is a Promise, we return that instead, and so the above actually sets `newPromise` to be:
// Promise<'abc'>
newPromise.then(abc => console.log(abc)); // get the resolved value from `newPromise` and log it. We see it is 'abc', and not Promise<'abc'>
因此,下面的代码做了一些事情:
.then(browser => (_browser = browser))
上面的代码会将 _browser
变量设置为 browser
值,该值来自 .launch()
[= 解析的 Promise returned 49=]
箭头函数将 return 值 browser
(因为 _browser = browser
将计算为 browser
)
.then()
将 return 一个新的 Promise,解析为 browser
值。发生这种情况是因为您从 .then()
的箭头函数中 return 的值变成了 return 由 .then()
编辑的 Promise 的解析值(参见上面关于.then
的 intracies。这意味着 紧接着 .then()
调用 return 的 Promise 解析之后的 .then()
调用至 browser
将能够在其箭头功能中访问它。
你的代码保存 browser
的值和由 browser.newPage()
编辑的 Promise return 在变量中的原因是它可以稍后在你的 Promise 链中访问它们在任意点。
请参阅代码注释以了解您的代码评估过程的说明:
// Promise<xyz> means that the Promise resolves to `xyz`,
// which you can access by using `.then(xyz => ...)` on the Promise
puppeteer
.launch() // returns Promise<browser> <---------------------|
.then(browser => (_browser = browser)) // sets _browser = browser, returns Promise<browser>
.then(browser => (_page = browser.newPage())) // sets _page = browser.newPage() (_page is now a Promise), returns `Promise<page>`, which is the promise returned `browser.newPage()` (see point 3 of `.then()` intracies above)
.then(page => page.goto('https://example.com')) // gets `page` from the previously returned Promise. This returns Promise<HTTPResponse> (as page.goto() returns Promise<HTTPResponse>) - this return value is ignored, as we don't need to use the `HTTPResponse`
.then(() => _page) // returns the `_page` Promise, this is done so the next `.then()` can access the resolved value of the `_page` Promise. (see point 3 of the above `.then()` intracies)
.then(page => page.screenshot({ path: 'example.png' })) // get the `page` value (which is the resolve value of the `_page` promise, returned by the above `.then()`), and return `Promise<Buffer>` - this value is ignored as it is not used in the next `.then()` call
.then(() => _browser.close()); // return Promise<BrowserContext>
与其执行所有这些操作,不如使用 async
/await
,如 docs 中所示,这样更容易理解:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
await page.screenshot({path: 'screenshot.png'});
await browser.close();
})();
我正在尝试学习 Node.js 和一些 await/promise,我遇到了这个例子 (https://remarkablemark.org/blog/2018/04/15/puppeteer-without-async-await/):
const puppeteer = require('puppeteer');
let _browser;
let _page;
puppeteer
.launch()
.then(browser => (_browser = browser))
.then(browser => (_page = browser.newPage()))
.then(page => page.goto('https://example.com'))
.then(() => _page)
.then(page => page.screenshot({ path: 'example.png' }))
.then(() => _browser.close());
我理解 .then(browser => (_browser = browser))
与 .then(function(browser) { return _browser = browser; })
相同,但我有点困惑为什么有些行使用 _browser
而有些行使用 browser
(与_page
).
我也不知道 .then(() => _page)
行是干什么用的。为什么这一行没有一个参数,它是前一个函数返回的参数,即 page.goto(...)
?我可能不太了解 Puppeteer 的 .then()
。
我正在尝试清理这段代码并使用 promises 和箭头函数:
puppeteer
.launch()
.then(function(browser) {
return browser.newPage();
})
.then(function(page) {
return page.goto(url).then(function() {
return page.content();
});
})
.then(function(html) {
// do something
})
.catch(function(err) {
//handle error
});
请注意以下事项:
var a; var b = a = 2;
。这将相同的值分配给变量a
和b
,因为a = 2
将值2
分配给变量a
和 returns 分配的值是2
然后分配给变量b
.(params?) => returnvalue
或(params?) => { return returnvalue; }
或function(params?) { return returnvalue; }
将是相同的函数定义。然而,编译器在几种情况下识别这些函数定义中的this
关键字的方式发生了一些变化,在这种情况下这不是一个需要关注的问题。Promise.then
return再次承诺 returnPromise
orvalue
ordefault undefined
.
解释:
let _browser;
let _page;
puppeteer
.launch()
.then(browser => (_browser = browser))
.then(browser => (_page = browser.newPage()))
.then(page => page.goto('https://example.com'))
// >>> Above .then may not be returning a page, so below .then will replace it with globally referenced _page
.then(() => _page)
.then(page => page.screenshot({ path: 'example.png' }))
// >>> Need a browser reference to close here
.then(() => _browser.close());
为了在整个承诺链中跟踪所需的 browser
或 page
引用,开发人员已在全局变量中分配引用并在整个过程中使用它们。
下面是建议的方法,以便在整个承诺链中清理和维护 [browser, page]
的引用。
puppeteer
.launch()
.then(browser => browser.newPage().then(page => [browser, page]))
.then(([browser, page]) => page.goto('https://example.com').then(() => [browser, page]))
.then(([browser, page]) => page.screenshot({ path: 'example.png' }).then(() => [browser, page]))
.then(([browser, page]) => browser.close());
如果您使用 async
和 await
,代码会显得更清晰。
puppeteer.launch()
returns 以 browser
解析的承诺,可在 then
,
_browser
是局部变量,它将 browser
赋值给它,因为在随后的所有 .then
中携带 browser
会很麻烦,例如, 你在最后看到的_browser.close()
假设用browser.close()
关闭原来的browser
,但是browser
不可用,这就是为什么你需要将它存储在变量中所以你可以做到 _browser.close()
与 _page
和 page
这是使用 async/await
的相同行为:
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
page.screenshot({ path: 'example.png' })
await browser.close()
})()
当谈到 .then(() => _page)
时,其目的是使 page
在下一个 .then
中可用,请参阅下面的代码段,其中 5
返回并可用下一个 .then
const wait = (time) => new Promise((res, rej) => setTimeout(() => res("hello"), time));
let _someVar;
wait(1000)
.then(msg => (_someVar = msg)) // this is .then(_browser => (_browser = browser))
.then(() => 5) // this is .then(() => _page)
.then(x => console.log(x));
console.log("a : ", _someVar);
setTimeout(() => {
console.log("b : ", _someVar);
}, 2000);
那是因为 page.goto() returns :
Promise which resolves to the main resource response. In case of multiple redirects, the navigation will resolve with the response of the last redirect.
() => _page
如果 page.goto
返回 page
则不需要
() => _page
,尽管我认为它可以省略并在下一个 _page.screenshot()
中执行 .then
当您为变量赋值时,该赋值的 return 值就是被赋值的值。例如:
let x;
const two = (x = 2); // x = 2 returns '2'
console.log(two); // 2 (return value of x = 2)
console.log(x); // 2 (x is set above to equal 2)
接下来,Promises 和 .then()
有一些需要注意的重要事项:
首先,
获得.then()
将 return 一个可以解析为值的新 Promise。 Promise 解析到的值可以使用.then(resolvedValue => ...)
.如前所述,
.then()
return是一个可以解析为值的 Promise。 Promise 解析到的值由您传递给.then()
函数 return 的函数决定。例如,如果您有.then(() => xyz)
,那么此.then()
方法调用的 Promise return 将是Promise<xyz>
。这是说明上面第 1 点和第 2 点的示例:
const promise = Promise.resolve(); // Promise<> (a promise that resolves to the value of undefined/nothing)
const promiseAbc = promise.then(() => 'abc'); // returns Promise<'abc'> (a Promise that resolves to 'abc')
promiseAbc.then(abc => console.log(abc)); // "extract" the resolved value from promiseAbc) (logs: 'abc')
- 如第 2 点所述,回调到
.then()
的 returned 值被.then()
用作 Promise returned 的解析值称呼。但是,当您 return 来自.then()
回调的 Promise 时,这会略有不同。 return 不是 return 解析为 Promise 的新 Promise,.then()
方法 return 是您从.then()
回调中 return 编辑的 Promise。这是一个清除此问题的示例:
const promise = Promise.resolve(); // Promise<> (a promise that resolves to the value of undefined/nothing)
const promiseAbc = Promise.resolve('abc'); // Promise<'abc'> (a promise that resolves to the value of 'abc')
const newPromise = promise.then(() => promiseAbc);
// You might expect that the above would return and set `newPromise` to be:
// Promise<Promise<'abc'>>
// But, as `promiseAbc` is a Promise, we return that instead, and so the above actually sets `newPromise` to be:
// Promise<'abc'>
newPromise.then(abc => console.log(abc)); // get the resolved value from `newPromise` and log it. We see it is 'abc', and not Promise<'abc'>
因此,下面的代码做了一些事情:
.then(browser => (_browser = browser))
上面的代码会将
_browser
变量设置为browser
值,该值来自.launch()
[= 解析的 Promise returned 49=]箭头函数将 return 值
browser
(因为_browser = browser
将计算为browser
).then()
将 return 一个新的 Promise,解析为browser
值。发生这种情况是因为您从.then()
的箭头函数中 return 的值变成了 return 由.then()
编辑的 Promise 的解析值(参见上面关于.then
的 intracies。这意味着 紧接着.then()
调用 return 的 Promise 解析之后的.then()
调用至browser
将能够在其箭头功能中访问它。
你的代码保存 browser
的值和由 browser.newPage()
编辑的 Promise return 在变量中的原因是它可以稍后在你的 Promise 链中访问它们在任意点。
请参阅代码注释以了解您的代码评估过程的说明:
// Promise<xyz> means that the Promise resolves to `xyz`,
// which you can access by using `.then(xyz => ...)` on the Promise
puppeteer
.launch() // returns Promise<browser> <---------------------|
.then(browser => (_browser = browser)) // sets _browser = browser, returns Promise<browser>
.then(browser => (_page = browser.newPage())) // sets _page = browser.newPage() (_page is now a Promise), returns `Promise<page>`, which is the promise returned `browser.newPage()` (see point 3 of `.then()` intracies above)
.then(page => page.goto('https://example.com')) // gets `page` from the previously returned Promise. This returns Promise<HTTPResponse> (as page.goto() returns Promise<HTTPResponse>) - this return value is ignored, as we don't need to use the `HTTPResponse`
.then(() => _page) // returns the `_page` Promise, this is done so the next `.then()` can access the resolved value of the `_page` Promise. (see point 3 of the above `.then()` intracies)
.then(page => page.screenshot({ path: 'example.png' })) // get the `page` value (which is the resolve value of the `_page` promise, returned by the above `.then()`), and return `Promise<Buffer>` - this value is ignored as it is not used in the next `.then()` call
.then(() => _browser.close()); // return Promise<BrowserContext>
与其执行所有这些操作,不如使用 async
/await
,如 docs 中所示,这样更容易理解:
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://example.com'); await page.screenshot({path: 'screenshot.png'}); await browser.close(); })();