迭代迭代中的setTimeout

时间:2015-06-10 07:39:26

标签: javascript node.js settimeout

我有以下代码,我想在setTimeout的每次迭代之间加上Myurl。有许多classes,每个都包含许多元素。

//Some calculations before...
var i = 0;
async.whilst(
function () {
    return i <= thefooz.length - 1;
},
function (innerCallback) {

    //Some calculations where I get classes array.

    async.forEachOfSeries(classes, function (Myurl, m, eachDone) {
        // Here I want a delay
        async.waterfall([
            function (next) {
                connection.query(
                    'SELECT * FROM mydata WHERE UrlLink=? LIMIT 1', [Myurl],
                    next
                );
            },
            function (results, fields, next) {
                if (results.length !== 0) {
                    console.log("Already Present");
                    return next();
                }
                console.log("New Thing!");
                request(options2, function (err, resp, body) {
                    if (!err && resp.statusCode == 200) {
                        var $ = cheerio.load(body);
                        //Some calculations, where I get AllLinks.
                        var post = {
                            ThisUrl: AllLinks[0],
                            Time: AllLinks[1],
                        };
                        var query = connection.query('Insert INTO mydata Set ?', post, next);
                    };
                });
            }
        ], eachDone);

    }, function (err) {
        if (err) throw err;
    });
    setTimeout(function () {
        i++;
        innerCallback();
        console.log("Done");
    }, 20000);

    //Some calculations after...

那么如何在Myurl中的每个async.waterfall之间设置延迟?说我想延迟5秒。我设法在setTimeout之间设置 每次async.whilst迭代但不在每次async.forEachOfSeries次迭代之间。它只是不等待,而是继续循环,直到每个async.forEachOfSeries完成,然后调用async.whilst setTimeout

EDIT: 队列解决方案不起作用。该解决方案似乎只是转到下一页和下一页等,而不输出到我的数据库。当然我可以用错误的方式应用它,但我真的试着按照例子说的那样做。

4 个答案:

答案 0 :(得分:7)

首先,我们必须实现一个简单的队列

队列

function Queue() {
  var obj = {};  
  var queue = [];
  var _delay;

  function next() {
    // If queue is empty stops execution
    if(queue.length == 0) return;

    // Prepare next call to next
    setTimeout(next, _delay);
    // Take out an element from the queue and execute it.
    (queue.shift())();          
  }

  // Add a new function to the queue
  obj.add = function (myFunc) {
    queue.push(myFunc);
  };

  // Start the queue execution passing the delay between each call
  obj.run = function(delay) {
    _delay = delay;

    // call next function
    next();
  }

  return obj;

}

然后我们在代码

中使用它
// create the queue
var myQueue = Queue();

async.forEachOfSeries(classes, function (Myurl, m, eachDone) {
  // Add the function to the queue
  myQueue.add(executeWaterfall.bind(this));
}, function (err) {
  if (err) throw err;
});

// Start the queue with 5 second delay
myQueue.run(5000);

function executeWaterfall() {
  async.waterfall([
    function (next) {
      connection.query(
        'SELECT * FROM mydata WHERE UrlLink=? LIMIT 1', [Myurl],
        next
      );
    },
    function (results, fields, next) {
      if (results.length !== 0) {
        console.log("Already Present");
        return next();
      }
      console.log("New Thing!");
      request(options2, function (err, resp, body) {
        if (!err && resp.statusCode == 200) {
          var $ = cheerio.load(body);
          //Some calculations, where I get AllLinks.
          var post = {
            ThisUrl: AllLinks[0],
            Time: AllLinks[1],
          };
          var query = connection.query('Insert INTO mydata Set ?', post, next);
        };
      });
    }
  ], eachDone);
}

这远非最佳,因为无论如何你正陷入所谓的厄运金字塔

加成

厄运金字塔

当使用正常回调连续处理异步操作时,您最终会在彼此之间嵌套调用;这种嵌套带来了更多的缩进,创造了一个金字塔(指向右边),因此得名“金字塔的厄运”。

解决方案

在这种情况下,最好使用一些承诺模式将代码保存在厄运金字塔中,以便解决此类问题。

答案 1 :(得分:2)

我认为你并不完全理解setTimeout如何运作:

(function () {
    var seconds=0;
[1,2,3].forEach(function(value) {
    setTimeout(function() {
        console.log('Showing value '+value+ 'at '+Date());
    },1000*seconds++);
})
})()

对于每个元素,此代码创建一个在一秒钟后执行的回调函数。请注意,JS是单线程的,因此代码实际上做的是将“执行”添加到队列中。因此,如果当前执行没有停止,则不会调用回调。因此,作为第二个参数传递给setTimeout函数的时间(以毫秒为单位)只是执行该代码的最短时间。

然后,这些回调的执行是按FIFO顺序执行的。

更新:以下是我正在解释的示例:

function myFunction() { 
    var test=0;
    setTimeout(function(){
        console.log("This is the current value of test: "+test); 
    }, 0);
    console.log("This is run first");
    for (var i=0;i<50;i++) {
        test++;
    }
    console.log("Main thread ending, not the callbacks will be executed");
} 

setTimeout将在执行前等待0(零),但由于主线程尚未完成,因此无法执行。然后,当循环结束时,执行回调,发现测试为50,而不是0.

答案 2 :(得分:0)

我对async库并不熟悉,但对我而言,async.waterfall看起来每次运行后都会调用eachdone,以便async.forEachOfSeries知道它应该执行下一次迭代。假设没有参数调用eachdone,我希望以下工作:

function executeWaterfall() {
  async.waterfall([
      ......
  ], function () { window.setTimeout(eachDone, 5000));
}

如果eachdone确实获得参数,您也必须将它们发送过来。

作为替代方案,我希望您可以在瀑布中添加另一个步骤,等待5秒。无论eachdone的参数如何,这都可以工作(但如果第三个瀑布函数需要更多参数,则可能会失败):

function executeWaterfall() {
  async.waterfall([
    function (next) {
      connection.query(
        'SELECT * FROM mydata WHERE UrlLink=? LIMIT 1', [Myurl],
        next
      );
    },
    function (results, fields, next) {
      if (results.length !== 0) {
        console.log("Already Present");
        return next();
      }
      console.log("New Thing!");
      request(options2, function (err, resp, body) {
        if (!err && resp.statusCode == 200) {
          var $ = cheerio.load(body);
          //Some calculations, where I get AllLinks.
          var post = {
            ThisUrl: AllLinks[0],
            Time: AllLinks[1],
          };
          var query = connection.query('Insert INTO mydata Set ?', post, next);
        };
      });
    },
    function (next) {
      window.setTimeout(next, 5000);
    }
  ], eachDone);
}

现在,我再次强调我不熟悉async并且所有示例都未经过测试。也许一切都是错误的,但这是我的直觉。

答案 3 :(得分:-3)

setTimeout只会延迟输出中显示的结果...它不会延迟setTimeout方法内部或外部方法的执行...在后台,线程将在setTimeout函数之后继续运行代码。 ..既然你正在使用异步,你就要使用ajax的COMPLETE方法,当你完成从服务器收到所有数据后将调用该方法