跳到主要内容

Web Worker

关于进程和线程

  • 一个程序运行时,就是一个进程,这里的程序可以是一段代码,也可以是一个exe应用程序
  • 线程是程序中一个执行流
  • 一个进程包含n个线程,同一个进程中的多个线程之间的所有变量共享
  • 多个进程之间变量不共享,同一个变量,各自有一份拷贝存在于每个进程中,互不影响

如果理解 Javascript 是单线程

代码依次按顺序执行

作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM

这决定了它只能是单线程,否则会带来很复杂的同步问题

比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?

单线程的 javascript 如何实现异步操作

概念

  • 同步:会逐行执行代码,会对后续代码造成阻塞,直至代码接收到预期的结果之后,才会继续向下执行任务
  • 异步:调用之后先不管结果,继续向下执行任务,常见的有:setTimeout, promise, 事件回调等

实现原理

  1. 浏览器是多线程的
  2. 主线程负责自上而下顺序执行,当遇到setTimeout函数后,便将其交给定时器线程去执行
  3. 定时器线程执行完之后,将 满足触发主线程条件的 回调函数放到任务队列中, 任务队列中的任务不会马上执行
  4. 待主线程代码执行完毕,才开始任务队列代码的执行

宏任务 & 微任务

  1. 异步任务分为两种:宏任务、微任务
  2. 两者包含
  3. 优先执行微任务,可以理解为:一个人去银行办理业务,一个业务办理完成后,柜员会问是否还有其他业务需要办理,这个时候的其他业务相当于是微任务,如果没有,才会继续叫号下一位(宏任务)

浏览器的 Event Loop

  1. 执行全局script的同步代码,形成一个执行栈; 碰到异步代码宏任务微任务区分,将宏任务加入宏任务队列微任务加入微任务队列任务队列的代码不立即执行
  2. 执行栈里的代码执行完毕后被清空,查看微任务队列是否有任务
    1. 若有,则将微任务队列加入执行栈,再在当前执行栈中,对微任务宏任务按以上顺序循环执行,形成一个Event Loop
    2. 若无,则查看宏任务队列是否有任务
      1. 若有,则将宏任务队列加入执行栈,再在当前执行栈中,对微任务宏任务按以上顺序循环执行,形成一个Event Loop
      2. 若无,则结束
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请求

Web Worker示例