clearInterval不停止间隔

时间:2018-02-01 21:40:00

标签: javascript node.js puppeteer

我正在尝试用无头镀铬/木偶操作者刮掉一些链接,同时向下滚动:

 let interval
 const linkScraper = async () => {
        return new Promise(async (resolve,reject) => {
               interval = setInterval(async () => {
                const visiblePosts = await page.$$("div[class*='wrapper']")
                const data = await handleVisiblePosts(visiblePosts)
                allPosts = {...allPosts, ...data}
                await scroll()
                const stop = await areWeAtTheBottom()
                if (stop) {              
                    console.log('STOPPING')              
                    clearInterval(interval)
                    resolve()                
                }
            }, 100); 

           })
          }

问题? clearInterval实际上并没有停止间隔。 stopping多次打印。

我怀疑它也可能是因为setinterval是异步的,需要它才能使用await

2 个答案:

答案 0 :(得分:1)

我可以找到以下可能的原因,为什么你的间隔不会停止:

  1. 您永远不会进入stop状态。
  2. 您以某种方式覆盖interval变量,因此不再保存您想要停止的实际间隔。
  3. 你得到了拒绝的承诺。
  4. 似乎没有任何理由为什么interval变量需要在linkScraper函数之外,并且将其置于函数内将阻止它以任何方式被覆盖。

    通过这么多await次调用,添加try / catch以捕获任何被拒绝的承诺并在出现错误时停止间隔似乎是明智的。

    如果您看到STOPPING被记录,那么您显然正在达到停止条件,因此看起来它必须是一个被覆盖的interval变量。

    这是一个无法覆盖interval变量的版本,并对代码清洁做了一些其他更改:

     const linkScraper = async () => {
         return new Promise((resolve, reject) => {
             const interval = setInterval(async () => {
                 try {
                     const visiblePosts = await page.$$("div[class*='wrapper']");
                     const data = await handleVisiblePosts(visiblePosts);
                     allPosts = { ...allPosts, ...data};
                     await scroll();
                     const stop = await areWeAtTheBottom();
                     if (stop) {
                         console.log('STOPPING');
                         clearInterval(interval);
                         resolve();
                     }
                 } catch(e) {
                     clearInterval(interval);
                     reject(e);
                 }
             }, 100);
    
         });
     }
    

    在清理此代码时,我遇到了几个问题:

    1. 您使用await的所有四个函数是否实际都返回了一个承诺?
    2. 并且allPosts在哪里宣布?
    3. 编辑:刚发现另一个问题。 setInterval()无法了解您的函数内的await次调用。请记住,外部功能实际上并没有阻止。一旦您点击await,它会立即返回。这意味着当您仍在处理第一个异步操作时,您可以获得另一个setInterval()回调。这会搞砸。以下是解决这个问题的方法:

      function delay(t) {
          return new Promise(resolve => {
              setTimeout(resolve, t);
          });
      }
      
      const linkScraper = () => {
              console.log("starting linkScraper");
      
              async function run() {
                  const visiblePosts = await page.$$("div[class*='wrapper']");
                  const data = await handleVisiblePosts(visiblePosts);
                  allPosts = { ...allPosts, ...data};
                  await scroll();
                  const stop = await areWeAtTheBottom();
                  if (stop) {
                      console.log('STOPPING');
                      return "stop";
                  }
                  return "continue";
              }
      
              return run().then(result => {
                  if (result === "continue") {
                      return delay(100).then(run);
                  }
              })
      
          });
      }
      

答案 1 :(得分:0)

我接受了jfriend00的解决方案,因为它指出了我正确的方向,我的略微修改,最终和工作版本看起来像这样:

const linkScraper = async () => {
    return new Promise(async (resolve, reject) => {
        const run = async () => {
            console.log("running")
            const visiblePosts = await page.$$("div[class*='wrapper']");
            const data = await handleVisiblePosts(visiblePosts);
            allPosts = {...allPosts, ...data};
            await scroll();
            const stop = await areWeAtTheBottom();
            if (stop) {
                console.log('STOPPING');
                resolve()
            } else {
                await page.waitFor(100)
                await run()
            }

        }

        await run()         
    })
}