我有一个模块可以在NodeJS中启动一些后台作业(作业是HTTP请求),下面是它的简化版本:
var
util = require('util'),
EE = require('events').EventEmitter,
Winston = require('winston');
var logger = new Winston.Logger({transports: [new Winston.transports.Console()]});
function Bot() {
EE.call(this);
this.model = ['job1','job2','job3'];
// null = never had a job, false = job started, true = job finished
this.jobs = {
'job1': null,
'job2': null,
'job3': null };
var mirror = this;
function start_job(job) {
var t = Math.floor(Math.random() * 10 + 1) * 1000;
logger.info('calling ' + job + ' for t=' + t);
setTimeout(function() {
logger.info('finished ' + job);
mirror.jobs[job] = true;
}, t);
}
this.on('start', function() {
logger.info('Starting');
while (mirror.isRunning()) {
for (var i=0; i<mirror.model.length; i++) {
var job = mirror.model[i];
var oldJob = mirror.jobs[job];
if (oldJob === null || oldJob === true) {
mirror.jobs[job] = false;
start_job(job);
}
}
// mirror.shutdown();
}
logger.info('Shutting down');
});
}
util.inherits(Bot, EE);
Bot.prototype.shutdown = function() {
this.running = false;
};
Bot.prototype.start = function() {
this.running = true;
this.emit('start');
};
Bot.prototype.isRunning = function() {
return this.running;
};
var bot = new Bot();
bot.start();
问题在于作业从未真正运行过。 start_job()
被调用,但setTimeout()
中的匿名函数从未触发。这是输出:
info: Starting
info: calling job1 for t=6000
info: calling job2 for t=5000
info: calling job3 for t=9000
此时,脚本在无限循环中挂起。
现在,如果我在第一次循环迭代后停止,通过取消注释mirror.shutdown()
,作业将按预期启动:
info: Starting
info: calling job1 for t=6000
info: calling job2 for t=9000
info: calling job3 for t=1000
info: Shutting down
info: finished job3
info: finished job1
info: finished job2
但这并不好。我不知道为什么会发生这种情况,但我是Node的新手,仍在努力解决一些问题。
我知道一个名为Background.js的模块,但我不知道这是否适用于这里或者它是多么稳定(似乎不是一个活跃的项目)。我可以尝试一下,但在继续之前我还是想了解这个问题。
答案 0 :(得分:1)
问题是node.js
是单线程的。 while循环继续运行并占用事件循环,因此setTimeout
没有机会触发。您需要将其放在setInterval
(或可能是递归setTimeout
)上,而不是使用while循环来启动作业。例如:
this.on('start', function() {
logger.info('Starting');
for (var i=0; i<mirror.model.length; i++) {
var job = mirror.model[i];
var oldJob = mirror.jobs[job];
if (oldJob === null || oldJob === true) {
mirror.jobs[job] = false;
start_job(job);
}
}
setTimeout(function(){mirror.start()}, 50);
logger.info('Shutting down');
});