What happend?
puppeteer 기반의 크롤러 기능 중 loop를 돌며 화면 내의 '다음' 이동 버튼을 클릭하며 데이터를 수집하는 부분을 개발하고 있었다.
클릭 후 자체적으로 setTimeOut을 활용해 만든 delay 함수를 호출시켜 대기 후 루프를 돌게 했는데도 자꾸만 몇개 데이터가 중복으로 들어가서 원인을 찾느라 몇 시간을 썼다.
What went wrong?
루프를 도는 함수 내에서 click에 await를 걸어주지 않았다.
여기서 주의할 점이, puppeteer에서 제공하는 $를 사용해 가져온 객체는 ElementHandle로 반환되고, querySelector를 사용해 가져온 객체는 그냥 Element로 반환된다는 점이다.
다른 로직에서는 eval 함수 내부에서 특정 버튼을 querySelector로 가져왔다.
그렇게 가져온 요소는 Element이므로 click 시에도 Promise를 반환하지 않으므로 그냥 await 없이 동기 호출했다.
이 기억때문에 오류가 난 부분에도 동일하게 await를 걸어주지 않았고, 따라서 click 이후 await 대기한 뒤 후속 작업을 진행해야 하는데 대기 없이 비동기 로직들은 남겨두고 루프가 추가로 돌아버렸고, 그래서 몇번의 중복 루프가 추가적으로 수행 & 중복 데이터가 입력된 것으로 보인다.
Lesson & Learned
따라서 puppeteer $ 함수로 가져온 객체를 click시, async 함수 내에서는 반드시 await로 호출해 대기하자.
끝.