node的process.nextTick()

949 阅读2分钟

概念简析:

Node.js是单线程的,除了系统IO之外,在它的事件轮询过程中,同一时间只会处理一个事件。你可以把事件轮询想象成一个大的队列,在每个时间点上,系统只会处理一个事件。即使你的电脑有多个CPU核心,你也无法同时并行的处理多个事件。但也就是这种特性使得node.js适合处理I/O型的应用,不适合那种CPU运算型的应用。在每个I/O型的应用中,你只需要给每一个输入输出定义一个回调函数即可,他们会自动加入到事件轮询的处理队列里。当I/O操作完成后,这个回调函数会被触发。然后系统会继续处理其他的请求。

process.nextTick()的意思就是定义出一个动作,并且让这个动作 在下一个事件轮询的时间点上执行

 案例:
 function foo() {
    console.error('foo');
  }
  process.nextTick(foo);
  console.error('bar');
 输出:
 bar
 foo 

使用场景

在多个事件里交叉执行CPU运算密集型的任务

var http = require('http');

function compute() {
    // performs complicated calculations continuously
    // ...
    process.nextTick(compute);
}

http.createServer(function(req, res) {
     res.writeHead(200, {'Content-Type': 'text/plain'});
     res.end('Hello World');
}).listen(5000, '127.0.0.1');

compute();

保持回调函数异步执行的原则

var client = net.connect(8124, function() { 
    console.log('client connected');
    client.write('world!\r\n');
});
在上面的代码里,如果因为某种原因,net.connect()变成同步执行的了,
回调函数就会被立刻执行,因此回调函数写到客户端的变量就永远不会被初始化了。
这种情况下我们就可以使用process.nextTick()把上面asyncFake()改成异步执行的:
function asyncReal(data, callback) {
    process.nextTick(function() {
        callback(data === 'foo');       
    });
}

用在事件触发过程中

来看一个例子,你想写一个库实现这样的功能:从源文件里读取数据,
当读取完毕后,触发一个事件同时传递读取的数据。可能你会这样写:

var EventEmitter = require('events').EventEmitter;

function StreamLibrary(resourceName) { 
    this.emit('start');

    // read from the file, and for every chunk read, do:        
    this.emit('data', chunkRead);       
}
StreamLibrary.prototype.__proto__ = EventEmitter.prototype;// inherit from EventEmitter
下面是一段调用这个库的客户端程序,我们想在程序中监听这些事件:

var stream = new StreamLibrary('fooResource');

stream.on('start', function() {
    console.log('Reading has started');
});

stream.on('data', function(chunk) {
    console.log('Received: ' + chunk);
});
但是上面的代码中,将永远接收不到“start”事件,因为在这个库实例化的时候,
“start”事件会被立刻触发执行,但此时事件的回调函数还没有准备好,
所以在客户端根本无法接收到这个事件。同样,我们可以用process.nextTick()
来改写事件触发的过程,下面是一个正确的版本:

function StreamLibrary(resourceName) {      
    var self = this;

    process.nextTick(function() {
        self.emit('start');
    });

    // read from the file, and for every chunk read, do:        
    this.emit('data', chunkRead);       
}