如何定期从另一个JavaScript函数中杀死并重新启动JavaScript函数

时间:2016-10-12 19:47:51

标签: javascript node.js

我写了一个刮刀,遍历网站上的每个页面并提取信息。有很多页面;如果这个程序不间断运行,则需要一周左右的时间才能完成。但是,当它试图从页面中提取信息时,每隔两三个小时它就会挂起,而且它永远不会继续。这令人沮丧,因为我不得不重新启动脚本。这是它的骨架,使用NodeJS运行:

val o: Option[Int] = Some(1)
o.map(o => println(o))
>> 1

o.flatMap(o => println(o))
>><console>:13: error: type mismatch;
 found   : Unit
 required: Option[?]
       o.flatMap(o => println(o))

我希望在这个或另一个文件中有一个运行scrape函数的函数,然后每2个小时就会杀死该函数并从它试图从中获取的最后一个索引重新启动它。我已经尝试过使用setTimeout来考虑配方,但我不确定如何在中途杀死一个函数堆栈。如果刮擦功能已经开始挂起,我也不希望重启功能失败。

对我来说,最好的方法是什么?这个问题的其他解决方案是受欢迎的,但即使从JavaScript知识的角度来看,我也想知道将来如何做到这一点。

这是我的功能更详细:

index = 0;
finalIndex = 50000;

function scrape(){
    if(index < finalIndex){
        //hit the website using nightmare, navigate to page, extract info, store as JSON
        console.log("finished scraping page number: ", index);
        index++;
        scrape();
    }
}

scrape();

有一些辅助函数,其代码我没有包含,但它们的名称应该是显而易见的,我不认为它们的功能是问题的重要部分。我还想明确表示我使用Node运行它,它从不在浏览器中运行。

3 个答案:

答案 0 :(得分:3)

我之前必须解决类似的问题,我选择的解决方案是确保每个页面在一定时间内完成,否则继续下一页。您可以将噩梦代码包含在承诺中,并使用Promise.race确保它在设定的时间内完成。然后,如果超时,请使用v2.8.0中引入的.halt api来防止内存泄漏和放弃进程。

它看起来像这样:

Promise.race([
  doNightmareCodeAndReturnPromise(nightmareInstance),
  new Promise((resolve, reject) => setTimeout(() => reject('timed out'), 5000))
])
.then(result => /* save result */)
.catch(error => {
  if (error === 'timed out') nightmareInstance.halt()
})

答案 1 :(得分:1)

JavaScript是单线程的,所以你不能从“外部”“杀死”运行函数,因为根本就没有“外部”(就像另一个线程)。

您使用JS的唯一多任务选项是协作式多任务处理 - 当您将函数设计为每次调用时都执行一小部分工作。

以下是这种分块功能的示例:

var index = 0;
var finalIndex = 50000;

var working = true; // if working == false then stop running.

function scrape(){

    if( !working )
      return;   

    if(index < finalIndex){
        // scrap code is here ... 
        console.log("finished scraping page number: ", index);
        index++;
        setTimeout(scrape); // schedule scrape for the next chunk (iteration)
                            // and return immediately
    }
}

// reset working variable in 60 seconds  
setTimeout( function() { working = false; }, 60000 );

scrape(); // start iterations

上面的这个刮擦功能可以完成单个废料操作,最后也可以 为下一次迭代安排自己。

另一个计时器用于将working变量设置为false。这将发出信号,以打破“循环”并停止。

答案 2 :(得分:0)

我认为你不能轻易杀死你的功能,但你可以稍微改变代码的结构。也许您的代码达到Count int c = elements.SelectMany(e => e.Attributes) .Count(a => a.Name == "City" && a.GetValue().ToString() == "Oakland"); 的限制并因此而停止。

尝试将代码转换为这样的for循环:

call stack