【问题标题】:Javascript Promises and console log?Javascript Promise 和控制台日志?
【发布时间】:2020-04-20 17:04:48
【问题描述】:

我需要有关 Javascript Promises 的帮助。

buttons - 是一个 NodeList。我是从puppeteer (API) 那里得到的。
我需要一个带有特定文本的按钮列表。
我将buttons 转换为真实按钮数组(page.evaluate API link):

  • 我通过数组映射,
  • 将其转换为按钮,
  • 检查文本,如果文本不是我需要的,请检查 return null
  • console.log 按钮文本 - 它显示了我需要的文本 - 所以一切都很好。
  • 然后我增加counter
  • 并返回转换后的按钮。

之后我过滤数组 - 检查非空元素。 我希望goodButtons 只包含我需要的按钮 - 带有正确的文本。

但是输出是

buttons 328
button: Confirm
button: Confirm
... 100 lines of "good button text" in total
button: Confirm
counter 0
good buttons 328

所以计数器不会增加一次(或者我缺少 async/awaitconsole.log 的技巧?)
但似乎goodButtons 数组以某种方式包含所有按钮,尽管我在控制台中登录的按钮文本似乎是正确的。

代码

const buttons = await page.$$('button[type="button"]')
console.log('buttons', await buttons.length)

let counter = 0;
let goodButtons = await buttons.map(async button => {
    const btnText = await page.evaluate(btn => btn.innerText, button);

    if (!['Confirm'].includes(btnText)) return null

    counter++
    console.log('button: ', btnText)

    return await button
}).filter(button => button !== null)

console.log('counter', counter)
console.log('good buttons', await goodButtons.length)

UPD(在 Felix Kling 评论之后)

let counter = 0;
let goodButtons = buttons.map(async button => {
        const btnText = await page.evaluate(btn => btn.innerText, button);

        if (!['Confirm', 'Подтвердить'].includes(btnText)) return null

        counter++

        return await button
})
goodButtons = await Promise.all(goodButtons)
goodButtons = goodButtons.filter(button => button !== null)

输出

buttons 328
counter 149
good buttons 328

【问题讨论】:

  • Array#map 不返回承诺。您需要使用Promise.all.filter 调用中的button 实际上是指一个promise,它始终是!== null
  • 您能说得更具体一点吗? @FelixKling 我把它改成了goodButtons = await Promise.all(goodButtons) 现在counter 工作了——它显示了很好的按钮数量。但是goodButtons 数组仍然包含所有 328 个元素。感谢您的快速回复。
  • 我用新代码和输出更新了问题
  • Promise.all 之后你不会过滤更新后的代码

标签: javascript promise async-await puppeteer


【解决方案1】:

async 函数返回一个承诺。

因此buttons.map( async function) 返回一个promise 数组,其中一些已通过null 实现(通过从map 函数返回null),而所有其他已通过返回button 元素句柄实现提供给 map 函数。

您可以使用Promise.all 将promise 数组转换为一个数组,您可以从中过滤掉null 值:

let counter = 0;

let goodButtons =  (await Promise.all(
    buttons.map(async button => {
        const btnText = await page.evaluate(btn => btn.innerText, button);

        if (!['Confirm', 'Подтвердить'].includes(btnText)) return null

        counter++
        return button
   }))
   .filter(button => button !== null)

请注意,数组的length 属性是一个数字,因此不需要await

类似button 在 puppeteer elementHandle 对象中,如果我正确阅读了文档,这不是一个承诺,所以它也不应该在它之前要求await

(编辑:感谢 Andrew P. - filter 函数必须应用于数组 由await Promise.all(.... 返回)

【讨论】:

  • 显然我们应该把它包装成这样(await Promise.all(...)).filter(...)
  • 同意,我改写了您建议的编辑,但结果应该是相同的。谢谢。
【解决方案2】:

这是@Felix Kling 的评论和@Ufuk 的提示之后的工作代码。

谢谢你们!

let counter = 0;
let goodButtons = buttons.map(async button => {
        const btnText = await page.evaluate(btn => btn.innerText, button);

        if (!['Confirm', 'Подтвердить'].includes(btnText)) return null

        counter++

        return await button
})
goodButtons = await Promise.all(goodButtons)
goodButtons = goodButtons.filter(button => button !== null)

输出

buttons 328
counter 149
good buttons 149

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-07
    • 2020-03-09
    • 1970-01-01
    • 2011-10-11
    • 1970-01-01
    • 1970-01-01
    • 2011-03-28
    相关资源
    最近更新 更多