共计 2044 个字符,预计需要花费 6 分钟才能阅读完成。
线程
javascript
是一门 单线程、异步、非阻塞、弱类型 脚本语言。
JS 的单线程是指一个 浏览器过程中只有一个 JS 的执行线程,同一时刻内只会有一段代码在执行,然而浏览器的渲染过程是多线程的, 而异步机制是浏览器的两个或以上常驻线程共同完成的。
同步异步 阻塞非阻塞
老张爱喝茶,废话不说,煮开水。出场人物:老张,水壶两把(一般水壶,简称水壶;会响的水壶,简称响水壶)。
1 老张把水壶放到火上,立等水开。(同步阻塞)老张感觉本人有点
2 老张把水壶放到火上,去客厅看电视,时不时去厨房看看水开没有。(同步非阻塞)老张还是感觉本人有点傻,于是变高端了,买了把会响笛的那种水壶。水开之后,能大声收回嘀~~~~ 的乐音。
3 老张把响水壶放到火上,立等水开。(异步阻塞)老张感觉这样傻等意义不大
4 老张把响水壶放到火上,去客厅看电视,水壶响之前不再去看它了,响了再去拿壶。(异步非阻塞)老张感觉本人聪慧了。
所谓同步异步,只是对于水壶而言。一般水壶,同步;响水壶,异步。尽管都能干活,但响水壶能够在本人竣工之后,提醒老张水开了。这是一般水壶所不能及的。同步只能让调用者去轮询本人(状况 2 中),造成老张效率的低下。所谓阻塞非阻塞,仅仅对于老张而言。立等的老张,阻塞;看电视的老张,非阻塞。状况 1 和状况 3 中老张就是阻塞的,媳妇喊他都不晓得。尽管 3 中响水壶是异步的,可对于立等的老张没有太大的意义。所以个别异步是配合非阻塞应用的,这样能力施展异步的效用。
——起源网络,作者不明。
事件循环
首先简略理解 JS 执行程序
step 1. 读入第一个代码块。
step 2. 语法分析,有错则报语法错误,并跳转到 step5。
step 3. 对 var 变量和 function 定义做“预编译解决”(预解析)。
step 4. 执行代码段,有错则报错(比方变量未定义)。
step 5. 如果还有下一个代码段,则读入下一个代码段,反复 step2。
step 6. 完结。
事件循环
- 所有同步工作都在主线程上执行,造成一个执行栈(execution context stack)。
- 主线程之外,还存在一个 ” 工作队列 ”(task queue)。只有异步工作有了运行后果,就在 ” 工作队列 ” 之中搁置一个事件。
- 一但 ” 执行栈 ” 中的所有同步工作执行结束,零碎就会读取 ” 工作队列 ”,看看外面有哪些事件。那些对应的异步工作,于是完结期待状态,进入执行栈,开始执行。
- 主线程一直反复下面的第三步。
5. 只有主线程空了,就会去读取 ” 工作队列 ”,这就是 JavaScript 的运行机制。这个过程会一直反复,这种机制就被称为事件循环(event loop)机制
宏工作 微工作
- 执行一个宏工作(栈中没有就从事件队列中获取)
- 执行过程中如果遇到微工作,就将它增加到微工作的工作队列中
- 宏工作执行结束后,立刻执行以后微工作队列中的所有微工作(顺次执行)
- 以后宏工作执行结束,开始查看渲染,而后 GUI 线程接管渲染
- 渲染结束后,JS 线程持续接管,开始下一个宏工作(从事件队列中获取)
宏工作 macro-task(Task)
一个 event loop 有一个或者多个 task 队列。task 工作源十分宽泛,比方 ajax 的 onload,click 事件,基本上咱们常常绑定的各种事件都是 task 工作源,还有数据库操作(IndexedDB),须要留神的是 setTimeout、setInterval、setImmediate 也是 task 工作源。总结来说 task 工作源:
- script
- setTimeout
- setInterval
- setImmediate
- I/O
- requestAnimationFrame
- UI rendering
微工作 micro-task(Job)
microtask 队列和 task 队列有些类似,都是先进先出的队列,由指定的工作源去提供工作,不同的是一个 event loop 里只有一个 microtask 队列。另外 microtask 执行机会和 Macrotasks 也有所差别
- process.nextTick
- promise
- Object.observe
- MutationObserver
宏工作和微工作的区别
- 宏队列能够有多个,微工作队列只有一个, 所以每创立一个新的 settimeout 都是一个新的宏工作队列,执行完一个宏工作队列后,都会去 checkpoint 微工作。
- 一个事件循环后,微工作队列执行完了,再执行宏工作队列
- 一个事件循环中,在执行完一个宏队列之后,就会去 check 微工作队列
自我提醒
console.log("start")
setTimeout(()=>{console.log(5)
},0)
Promise.resolve().then(()=>{setTimeout(()=>{console.log(1)
},0)
console.log(2)
}).then(()=>{console.log(3)
})
console.log(4)
// process.nextTick(()=>{// console.log(6)
// })
console.log("end")