title: How to await inside setInterval in JS?
body: <p>I have a code segment that looks like this:</p>
  
  <pre><code>async function autoScroll(page, maxDate = null) {
    await page.evaluate(async () =&gt; {
      await new Promise(async (resolve, reject) =&gt; {
          try {
              const scrollHeight = document.body.scrollHeight;
              let lastScrollTop = 0;
  
              const interval = setInterval(async () =&gt; {
                  window.scrollBy(0, scrollHeight);
                  const scrollTop = document.documentElement.scrollTop;
                  let lastDate = null;
  
                  if (maxDate) {
                      const html = new XMLSerializer().serializeToString(document.doctype) + document.documentElement.outerHTML;
  
                      await extractDate(html).then((date) =&gt; {
                          lastDate = date;
                      });
                  }
  
                  if (scrollTop === lastScrollTop || 
                      (maxDate &amp;&amp; lastDate &amp;&amp; maxDate.getTime() &gt;= lastDate.getTime())) {
                      clearInterval(interval);
                      resolve();
                  } else {
                      lastScrollTop = scrollTop;
                  }
              }, 2000);
          } catch (err) {
              console.error(err);
              reject(err.toString());
          }
      });
  });
  }
  </code></pre>
  
  <p>Where <code>extractDate</code> method has the following form:</p>
  
  <pre><code>function extractDate(html) {
      return new Promise((resolve, reject) =&gt; {
          // Rest removed for brevity.
          resolve(result);
      });
  }
  </code></pre>
  
  <p>Now the problem is that, my code keeps scrolling, but it doesn't wait for the other stuff inside <code>setInterval</code> to finish, as it keeps scrolling every 2 seconds, but normally <code>extractDate</code> function should take longer than 2 seconds, so I actually want to await for everything inside <code>setInterval</code> to finish before making the call to the new interval.</p>
  
  <p>Because of the async nature of stuff, I didn't manage to <code>console.log</code> stuff so see the behavior of the code.</p>
  
  <p>So, how can I make sure that everything inside <code>setInterval</code> finishes before making the next interval call?</p>
  
  <p><strong>EDIT:</strong></p>
  
  <p>This solution using <code>setTimeout</code> scrolls just once and throws unhandled promise rejection error with puppeteer.</p>
  
  <pre><code> async function autoScroll(page, maxDate = null) {
       await page.evaluate(async () =&gt; {
          await new Promise(async (resolve, reject) =&gt; {
              try {
                 const scrollHeight = document.body.scrollHeight;
                 let lastScrollTop = 0;
  
                  const interval = async function() {
                      window.scrollBy(0, scrollHeight);
                      const scrollTop = document.documentElement.scrollTop;
                      let lastDate = null;
  
                      if (maxDate) {
                          const html = new XMLSerializer().serializeToString(document.doctype) + document.documentElement.outerHTML;
                          await extractDate(html).then((date) =&gt; {
                              lastDate = date;
                          });
                      }
  
                      if (scrollTop === lastScrollTop || 
                         (maxDate &amp;&amp; lastDate &amp;&amp; maxDate.getTime() &gt;= lastDate.getTime())) {
                          resolve();
                      } else {
                          lastScrollTop = scrollTop;
                          setTimeout(interval, 2000);
                      }
                  }
  
                  setTimeout(interval, 2000);
  
              } catch (err) {
                  console.error(err);
                  reject(err.toString());
              }
          });
      });
  }
  </code></pre>