Javascript Обещания и консольный журнал? - PullRequest
1 голос
/ 20 апреля 2020

Мне нужна помощь с Javascript Обещаниями.

buttons - это NodeList. Я получаю его от puppeteer ( API ).
Мне нужен список кнопок с указанным c текстом.
Я преобразую 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 / await и console.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 (после комментария Феликса Клинга)

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

Ответы [ 2 ]

1 голос
/ 20 апреля 2020

async функции возвращают обещание.

Следовательно, buttons.map( async function) возвращает массив обещаний, некоторые из которых были выполнены с null (возвращая null из функции карты), в то время как все остальные были выполнены путем возврата дескриптора элемента button, предоставленного функции карты.

Вы можете использовать Promise.all для преобразования массива обещаний в массив, из которого вы можете отфильтровать null values:

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 в элементе кукловодаHandle объект, а не обещание, если я правильно прочитал документацию, поэтому для него также не требуется await.

(Редактировать: благодаря Эндрю П. - функция фильтра должна применяться к массив, возвращаемый await Promise.all(....)

1 голос
/ 20 апреля 2020

Это рабочий код после комментария @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
...