일반적으로, 당신은 "[에디션]의 작업을 완료"한 tempPage
때까지 실행을 일시 중지 할 await tempPage.click("a.orange")
에 의존 할 수 없다. 동기식으로 실행되는 슈퍼 간단한 코드의 경우 작동 할 수 있습니다. 그러나 일반적으로, 당신은 그것에 의지 할 수 없습니다.
클릭이 Ajax 연산을 트리거하거나 CSS 애니메이션을 시작하거나 즉시 계산할 수없는 계산을 시작하거나 새 페이지를 열면 대기중인 결과는 비동기이며 .click
메서드는이 비동기 작업이 완료 될 때까지 대기하지 않습니다.
무엇을 할 수 있습니까? 어떤 경우에는 페이지에서 실행중인 코드에 연결하여 중요한 이벤트가 발생할 때까지 기다릴 수 있습니다. 예를 들어 Ajax 작업이 완료 될 때까지 기다리고 페이지의 코드가 jQuery를 사용하는 경우 ajaxComplete
을 사용하여 작업이 완료된시기를 감지 할 수 있습니다. 조작이 완료 될 때를 감지하기 위해 이벤트 시스템에 연결할 수 없으면, 조작이 완료되었다는 증거를 기다리기 위해 페이지를 폴링해야합니다.
const puppeteer = require('puppeteer');
function getResults(page) {
return page.evaluate(() => ({
clicked: window.clicked,
asynchronousResponse: window.asynchronousResponse,
}));
}
puppeteer.launch().then(async browser => {
const page = await browser.newPage();
await page.goto("https://example.com");
// We add a button to the page that will click later.
await page.evaluate(() => {
const button = document.createElement("button");
button.id = "myButton";
button.textContent = "My Button";
document.body.appendChild(button);
window.clicked = 0;
window.asynchronousResponse = 0;
button.addEventListener("click",() => {
// Synchronous operation
window.clicked++;
// Asynchronous operation.
setTimeout(() => {
window.asynchronousResponse++;
}, 1000);
});
});
console.log("before clicks", await getResults(page));
const button = await page.$("#myButton");
await button.click();
await button.click();
console.log("after clicks", await getResults(page));
await page.waitForFunction(() => window.asynchronousResponse === 2);
console.log("after wait", await getResults(page));
await browser.close();
});
setTimeout
코드 클릭 시작 비동기 작업의 종류를 시뮬레이션 : 여기
문제를 보여주는 예이다. 이 코드를 실행하면
, 당신은 콘솔에서 볼 수 있습니다 :
before click { clicked: 0, asynchronousResponse: 0 }
after click { clicked: 2, asynchronousResponse: 0 }
after wait { clicked: 2, asynchronousResponse: 2 }
당신은 clicked
즉시 두 번 클릭으로 두 배 증가 것을 알 수있다. 그러나 asynchronousResponse
이 증가하기까지 시간이 걸립니다. 문 await page.waitForFunction(() => window.asynchronousResponse === 2)
은 우리가 기다리고있는 상태가 실현 될 때까지 페이지를 폴링합니다.
버튼에서 탭을 닫았다 고 언급했습니다. 열기 탭과 닫기 탭은 비동기 작업입니다.다음 예는 다음과 같습니다
puppeteer.launch().then(async browser => {
let pages = await browser.pages();
console.log("number of pages", pages.length);
const page = pages[0];
await page.goto("https://example.com");
await page.evaluate(() => {
window.open("https://example.com");
});
do {
pages = await browser.pages();
// For whatever reason, I need to have this here otherwise
// browser.pages() always returns the same value. And the loop
// never terminates.
await page.evaluate(() => {});
console.log("number of pages after evaluating open", pages.length);
} while (pages.length === 1);
let tempPage = pages[pages.length - 1];
// Add a button that will close the page when we click it.
tempPage.evaluate(() => {
const button = document.createElement("button");
button.id = "myButton";
button.textContent = "My Button";
document.body.appendChild(button);
window.clicked = 0;
window.asynchronousResponse = 0;
button.addEventListener("click",() => {
window.close();
});
});
const button = await tempPage.$("#myButton");
await button.click();
do {
pages = await browser.pages();
// For whatever reason, I need to have this here otherwise
// browser.pages() always returns the same value. And the loop
// never terminates.
await page.evaluate(() => {});
console.log("number of pages after click", pages.length);
} while (pages.length > 1);
await browser.close();
});
내가 위를 실행
, 내가 얻을 :
number of pages 1
number of pages after evaluating open 1
number of pages after evaluating open 1
number of pages after evaluating open 2
number of pages after click 2
number of pages after click 1
당신은 window.open()
전에 조금 걸립니다 볼 수 있고 window.close()
가 감지 효과가있다. 귀하의 코멘트에서
당신은 또한 썼다 :
내가 await
내가 그것을 동기에 비동기 기능을 전환 언급하지 않았다 동기 한
에 비동기 기능을 설정 기본적으로 어떤 알았는데 사람. 현재 코드가 비동기 작업의 해결 또는 거부 약속을 기다리게합니다. 그러나 여기서 중요한 문제는 자바 스크립트 코드를 실행하는 두 개의 가상 머신 즉, puppeteer
을 실행하는 노드와 브라우저를 제어하는 스크립트가 있다는 것입니다. 브라우저 자체에는 자체 JavaScript 가상 머신이 있습니다. 노드 쪽에서 사용하는 await
은 노드 코드에만 영향을 미치며 브라우저에서 실행되는 코드에는 영향을주지 않습니다.
await page.evaluate(() => { some code; })
과 같은 것을 보았을 때 혼란 스러울 수 있습니다. 모든 것이 하나의 가상 머신에서 실행되는 것처럼 보이지만 실제로는 그렇지 않습니다. puppeteer
은 전달 된 매개 변수를 .evaluate
으로 가져 와서 직렬화 한 다음 브라우저로 보내 실행합니다. const button = ...
뒤에 위 스크립트에서 await page.evaluate(() => { button.click(); });
과 같은 것을 추가해보세요. 이런 식으로 뭔가 : 스크립트에서
const button = await tempPage.$("#myButton");
await button.click();
await page.evaluate(() => { button.click(); });
는 button
는 page.evaluate
전에 정의되어 있지만거야 button
때문에 page.evaluate
실행은 브라우저 측에 정의되어 있지 않은 경우 ReferenceError
!