Различия между evaluate и evaluateHandle

Playwright предоставляет мощный и гибкий API для работы с браузером и автоматизации веб-тестирования. Одной из ключевых возможностей является выполнение JavaScript-кода на странице с помощью методов evaluate и evaluateHandle. Эти два метода часто используются для взаимодействия с содержимым страницы, но у них есть важные различия в способе работы и применении.

Метод evaluate

Метод evaluate выполняет переданный JavaScript-код в контексте страницы и возвращает результат выполнения этого кода. Этот метод используется, когда требуется получить какой-либо результат или выполнить действие, не требующее дальнейшей работы с объектами страницы после выполнения кода.

Пример использования evaluate:

const result = await page.evaluate(() => {
  return document.title; // Возвращает заголовок страницы
});
console.log(result);

В этом примере код, переданный в evaluate, выполняется в контексте браузера. Результат выполнения — это значение, возвращаемое из функции (в данном случае — заголовок страницы). Этот результат передается обратно в контекст Node.js, где можно работать с ним, например, вывести в консоль.

Ключевые моменты:
  • Метод evaluate работает с данными, которые могут быть легко сериализованы (например, строки, числа, массивы, объекты).
  • Внутри функции, передаваемой в evaluate, можно использовать любые глобальные объекты и API, доступные на странице, такие как document, window и другие.
  • После выполнения evaluate результат передается в Node.js, и дальнейшая работа с объектами страницы невозможна без дополнительных действий.

Метод evaluateHandle

Метод evaluateHandle работает схоже с evaluate, но вместо простого результата возвращает JSHandle — специальный объект, который представляет собой ссылку на элемент на странице или другой объект, доступный через JavaScript в контексте браузера. Этот объект можно использовать для дальнейших взаимодействий с DOM, например, извлекать свойства или выполнять другие операции.

Пример использования evaluateHandle:

const elementHandle = await page.evaluateHandle(() => {
  return document.querySelector('h1'); // Возвращает хэндл первого заголовка h1
});
const text = await elementHandle.evaluate(el => el.textContent); // Получаем текст заголовка
console.log(text);

В данном примере evaluateHandle возвращает не простой результат, а ссылку на элемент h1. Используя объект elementHandle, можно продолжать работать с этим элементом, например, извлечь его текстовое содержимое.

Ключевые моменты:
  • Метод evaluateHandle возвращает объект JSHandle, который является ссылкой на элемент или другой объект страницы.
  • Этот объект можно использовать для дальнейших манипуляций, например, извлечения свойств или взаимодействия с элементами, не требуя выполнения дополнительного кода в браузере.
  • JSHandle позволяет работать с объектами, которые невозможно вернуть с помощью обычного JavaScript, например, DOM-элементы или функции.

Сравнение evaluate и evaluateHandle

  1. Тип возвращаемого значения:

    • evaluate возвращает примитивные значения, такие как строки, числа, булевы значения или объекты, которые можно сериализовать.
    • evaluateHandle возвращает объект JSHandle, который представляет собой ссылку на элемент или объект в браузере. Это позволяет проводить дополнительные операции с этим объектом.
  2. Применение:

    • evaluate используется, когда нужно получить простое значение, такое как текст страницы, заголовок, мета-данные и т.п.
    • evaluateHandle используется, когда нужно работать с элементами страницы, например, получать их свойства, манипулировать ими или выполнять дополнительные операции.
  3. Поддержка DOM-объектов:

    • evaluate ограничен возвратом сериализуемых данных, и взаимодействие с DOM-элементами напрямую невозможно.
    • evaluateHandle дает возможность работать с объектами DOM через JSHandle, что расширяет возможности для взаимодействия с элементами страницы.

Примеры использования

Пример с evaluate:

Получение количества элементов на странице:

const numberOfElements = await page.evaluate(() => {
  return document.querySelectorAll('div').length; // Количество всех div на странице
});
console.log(numberOfElements);
Пример с evaluateHandle:

Получение и манипуляция DOM-элементом:

const handle = await page.evaluateHandle(() => document.querySelector('h1'));
const textContent = await handle.evaluate(el => el.textContent); // Получаем текст заголовка
console.log(textContent);

В данном примере evaluateHandle позволяет работать с элементом h1 как с объектом, что невозможно при использовании evaluate.

Заключение

Выбор между evaluate и evaluateHandle зависит от конкретной задачи. Если нужно получить результат простого вычисления или данных, достаточно использовать evaluate. Когда требуется взаимодействие с объектами страницы, такими как DOM-элементы, лучше применять evaluateHandle, чтобы получить доступ к этим объектам через JSHandle и проводить дополнительные манипуляции с ними.