Web Worker
关于进程和线程
- 一个程序运行时,就是一个进程,这里的程序可以是一段代码,也可以是一个exe应用程序
- 线程是程序中一个执行流
- 一个进程包含n个线程,同一个进程中的多个线程之间的所有变量共享
- 多个进程之间变量不共享,同一个变量,各自有一份拷贝存在于每个进程中,互不影响
如果理解 Javascript 是单线程
代码依次按顺序执行
作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM
这决定了它只能是单线程,否则会带来很复杂的同步问题
比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
单线程的 javascript 如何实现异步操作
概念
- 同步:会逐行执行代码,会对后续代码造成阻塞,直至代码接收到预期的结果之后,才会继续向下执行任务
- 异步:调用之后先不管结果,继续向下执行任务,常见的有:setTimeout, promise, 事件回调等
实现原理
- 浏览器是多线程的
- 主线程负责自上而下顺序执行,当遇到setTimeout函数后,便将其交给
定时器线程
去执行 定时器线程
执行完之后,将 满足触发主线程条件的 回调函数放到任务队列中
,任务队列
中的任务不会马上执行- 待主线程代码执行完毕,才开始
任务队列
代码的执行
宏任务 & 微任务
- 异步任务分为两种:宏任务、微任务
- 两者包含
- 优先执行
微任务
,可以理解为:一个人去银行办理业务,一个业务办理完成后,柜员会问是否还有其他业务需要办理,这个时候的其他业务相当于是微任务
,如果没有,才会继续叫号下一位(宏任务
)
浏览器的 Event Loop
- 执行全局script的同步代码,形成一个
执行栈
; 碰到异步代码
按宏任务
和微任务
区分,将宏任务
加入宏任务队列
,微任务
加入微任务队列
,任务队列
的代码不立即执行 执行栈
里的代码执行完毕后被清空,查看微任务队列
是否有任务- 若有,则将
微任务队列
加入执行栈
,再在当前执行栈
中,对微任务
和宏任务
按以上顺序循环执行,形成一个Event Loop
- 若无,则查看
宏任务队列
是否有任务- 若有,则将
宏任务队列
加入执行栈
,再在当前执行栈
中,对微任务
和宏任务
按以上顺序循环执行,形成一个Event Loop
- 若无,则结束
- 若有,则将
- 若有,则将
console.log('start');
setTimeout(() => {
console.log('time1');
Promise.resolve().then(() => {
console.log('promise1');
})
}, 0);
setTimeout(() => {
console.log('time2');
Promise.resolve().then(() => {
console.log('promise2');
})
}, 0);
Promise.resolve().then(() => {
console.log('promise3');
});
console.log('end');
// 输出
// start
// end
// promise3
// time1
// time2
// promise1
// promise2
HTML5提出的 Web Worker 标准
- 在独立于js主线程的后台线程中,执行一个新的脚本
- 不影响主线程,不影响js的单线程本质
Web Worker 的限制
- 不能操作DOM: 新的线程下操作DOM,会产生浏览器渲染的同步问题;
- 不能使用
document
,window
,parent
对象,但可以访问location
,navigator
对象 - Worker线程与主线程必须是同源,且不能使用
file://
文件系统的文件 - Worker线程与主线程之间,使用
postMessage
通讯 - 可以使用
XMLHttpRequest
对象发送AJAX
请求