操作系统的一些知识
当我按下空格键,操作系统是咋知道的
- 键盘下面是个复杂的电路。当我按下空格键会有一个电流,这个电流会触发空格键的信息(比如空格键的信息是个数字101)
- 这个101会被传给操作系统
- 操作系统通知浏览器这个键盘事件
- 浏览器接收到操作系统给他的这个键盘事件,得到空格键信息,就会显示在input里面
其实按下键盘后是存到一个队列里,操作系统是每五秒就去队列里看看有没有信息(这叫轮询)。没有就走,有就传给其他软件等。
EventLoop是虚拟的概念,只是阶段的转移
js只有单线程,那么问题就来了异步的事件,到底是谁在等?答案是C++,底层事件通过轮询实现。
js遇到异步事件,发请求给C++,让c++执行
Node.js
浏览器可以执行js代码,node.js也可以执行js代码,EventLoop是nodejs的概念
nodejs看见setimeout会1. 开启事件循环 2. 执行setimeout js代码 但是两个先后顺序不知道因为两个都需要时间
- Node.js的EventLoop有六个阶段。我们只需要了解三个阶段:timers、poll、check
- API
- setTimeout里的函数fn会存在timers 数组里,放进去之后在poll阶段等1000ms,快速进入timers阶段执行fn
- setImmediate里的函数会存在check阶段。
- nextTick会放在当前阶段的后面,跳转到下一阶段之前。
- Promise不讨论了。
settimeout(f1,0)和setmmediate(f2)
循环首先进入poll阶段。
如果event loop开的很快,发现现在没有f1,timers里没东西,那么执行js时从poll开始
如果开的很慢,js(settimeout)执行完了,那么f1在timers里
如果有就进入check阶段执行这些callback。但同时也会检查是否有到期的timer,如果有,就把这些到期的timer的callback按照调用顺序放到timer queue中,之后循环会进入timer阶段执行queue中的 callback。
这两者的顺序是不固定的,收到代码运行的环境的影响。如果两者的queue都是空的,那么loop会在poll阶段停留,直到有一个i/o事件返回,循环会进入i/o callback阶段并立即执行这个事件的callback。
setTimeout(() => {
console.log('timeout');
}, 0);
setImmediate(() => {
console.log('immediate');
});
如果外面再加一层setimeout,那么事件循环早已经开完了,已经变成了poll阶段
Chrome
- Chrome的EventLoop有两个阶段:宏任务(一会儿)和微任务(马上)
- API
- setTimeout和setImmediate里的函数会存在宏任务(一会儿)阶段
- promise.then(fn)的函数在resolve会存在微任务(马上)阶段
- await转化成promise
- 浏览器没有C++线程,只会在进行完同步任务后检查一下异步队列。
new Promise(fn)马上执行fn的,有微任务执行微任务,执行完之后执行宏任务
process.nextTick() 并不是 event loop 的一部分。实际上,不管 event loop 当前处于哪个阶段,nextTick 队列都是在当前阶段后就被执行了。放到当前队列最后。
一般来说,事件循环在poll阶段停留着,等事件到了,或者有check队列
浏览器的loop详解
Javascript 有一个 main thread 主线程和 call-stack 调用栈(执行栈),所有的任务都会被放到调用栈等待主线程执行。
Javascript单线程任务被分为同步任务和异步任务,同步任务会在调用栈中按照顺序等待主线程依次执行,异步任务会在异步任务有了结果后,将注册的回调函数放入任务队列中等待主线程空闲的时候(调用栈被清空),被读取到栈内等待主线程的执行。
MacroTask(宏任务)
script
全部代码、setTimeout
、setInterval
、setImmediate
(浏览器暂时不支持)、I/O
、UI Rendering
。- script全部代码指的是先执行完所有script代码
MicroTask(微任务)
- Promise
执行栈在执行完同步任务后,查看执行栈是否为空,如果执行栈为空,就会去检查微任务(microTask
)队列是否为空,如果为空的话,就执行Task
(宏任务),否则就一次性执行完所有微任务。
每次单个宏任务执行完毕后,检查微任务(microTask
)队列是否为空,如果不为空的话,会按照先入先出的规则全部执行完微任务(microTask
)后,设置微任务(microTask
)队列为null
,然后再执行宏任务,如此循环。