Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nodejs中的event loop #1

Open
UNDERCOVERj opened this issue Mar 24, 2018 · 0 comments
Open

nodejs中的event loop #1

UNDERCOVERj opened this issue Mar 24, 2018 · 0 comments

Comments

@UNDERCOVERj
Copy link
Owner

概念

我们知道,js是单线程语言。运行时,有一个主线程,主线程执行完执行栈的任务后去检查异步的任务队列。如果异步事件触发,则将其加入到主线程的执行栈

event loop的操作顺序

操作顺序

每个时期都有一个先进先出的回调函数队列

当event loop进入到一个给定的时期时,它将特定于那个阶段执行任意操作,然后执行回调函数

当队列执行完,或者callback到达上限时,事件循环就会进入下一个时期

timers

这个时期执行setTimeout和setInterval的回调函数

一个回调函数执行的时间期限,肯能多余明确的time

举个例子:

假设读文件花95ms,callback花10ms。timer是100ms。则总共是花了105ms

function readAnotherFile () {
	readFile('/a/b/file', costTime) // cost 95ms
}

function costTIme () {
	var date = Date.now();
	while (Date.now() - date < 10) {
		// >10ms
	}
}

setTimeout(() => {
	console.log('complete')
}, 100)

I/O callbacks

这个时期执行一些系统操作的callbacks,比如说TCP errors

poll

获取新的 I/O 事件;nodejs这时会适当进行阻塞

poll时期有两个功能:

  1. 执行时间已经到了的timers的脚本
  2. 处理poll queue中的events

当event loop进入poll时期,如果没有预定的timers,则会出现两种情况

  1. 如果poll queue不是空的,event loop会循环访问它的callback queue,同步的执行它们,直到任意队列消耗完。或者等到系统依赖的时间期限到达
  2. 如果poll queue是空的
    1. 如果有setImmediate(), event loop会终止poll时期,进而转到check时期,执行安排好了的scripts
    2. 如果没有setImmediate(),event loop会等到有callback添加到queue,并立即执行它们

注意: 一旦poll queue空了,event loop会检查哪个timer的时间到了,如果一个或多个准备好了,event loop会回到timers时期去执行callbacks

check

这个时期允许poll时期一完成,就执行callbacks,如果poll时期变得闲置了并且setImmediate()已经加入队列了,event loop会继续check而不是等待

setImmediate()运行在一个与event loop不一样的单独的时期

close callbacks

如果一个socket或者handle,被中断,会触发close事件,否则它会被process.nextTick()触发

setImmediate() vs setTimeout()

  • 一旦poll时期完成,setImmediate就会执行

setImmediate总是将事件注册到下一轮Event Loop

多个setImmediate可能则需要多次loop才能执行完

  • 当某个timer时间到达时,setTimeout的callback就会被执行

setImmediate和setTimeout的执行顺序是不尽相同的

setTimeout(function () {
	console.log('time out 1')
}, 0)
setImmediate(function () {
	console.log('immediate 1')
});
// time out 1
// immediate 1

----
// immediate 1
// time out 1

然而在i/o周期,通常setImmediate先回调

const fs = require('fs')

fs.readFile('./global.js', (err) => {
	setTimeout(function () {
		console.log('time out 1')
	}, 0)
	setImmediate(function () {
		console.log('immediate 1')
	});
})
  • setImmediate的有点

如果在i/o周期,会先于任何timer执行

process.nextTick()

nextTickQueue会在当前操作完成后被处理,不管处于event loop的哪个阶段

在特定时期的任何时间调用process.nextTick,所有callbacks都会在event loop继续之前被调用

每次事件轮询后,在额外的I/O执行前,next tick队列都会优先执行。 递归调用nextTick callbacks 会阻塞任何I/O操作,就像一个while(true); 循环一样。

process.nextTick() vs setImmediate()

多个process.nextTick语句总是在当前"执行栈"一次执行完,多个setImmediate可能则需要多次loop才能执行完。

process.nextTick()属于idle观察者,setImmediate()属于check观察者。在每一个轮循环检查中,idle观察者先于I/O观察者,I/O观察者先于check观察者

process.nextTick方法可以在当前"执行栈"的尾部----下一次Event Loop(主线程读取"任务队列")之前----触发回调函数。也就是说,它指定的任务总是发生在所有异步任务之前。setImmediate方法则是在当前"任务队列"的尾部添加事件,也就是说,它指定的任务总是在下一次Event Loop时执行,这与setTimeout(fn, 0)很像。

在行为上,process.nextTick在每轮循环中会将数组中的回调函数全部执行完。而setImmediate在每轮循环中执行链表的一个回调函数

例子

解释:

下列代码,首先,process.nextTick的回调函数肯定先执行。由于setTimeout的time为0,会立即执行,所以优先于setImmediate。如果time>0,则顺序就不一样了

总的顺序:

nextTick

setTimeout(callback, after);

setImmediate(callback, arg1, arg2, arg3);

setImmediate(function () {
	console.log('setImmediate(callback, arg1, arg2, arg3);')
});
setTimeout(function () {
	console.log('setTimeout(callback, after);')
}, 0);
process.nextTick(function () {
	console.log('nextTick')
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant