浏览器知识点6:消息队列

500 阅读3分钟

消息队列:数据结构,存放要执行的任务,先进先出

线程模型:

  • 第一版:单线程按照顺序处理确定好的任务
  • 第二版:引入循环语句和事件系统,解决线程执行过程中接受并处理新任务
  • 第三版:引入消息队列,接受其他线程发送来的任务
  • 第四版:引入IO线程,通过IPC把任务发给IO线程,然后再把任务发送给页面主线程

消息队列中任务类型:

  • 内部消息:鼠标事件、微任务、文件读写、websocket、javascript定时器等(主线程)
  • 页面相关:js执行、解析dom、样式计算、布局计算、css动画等(主线程)

页面单线程的缺点

  • 如何处理高优先级任务:微任务权衡效率和实时性

  • 消息队列里的任务称为宏任务,宏任务中又包含了一个微任务队列

  • 如何解决单个任务执行时间过长:回调

setTimeout

function showName(){
  console.log("掘金社区")
}
var timerID = setTimeout(showName,200);

// timerID -> 整数,定时器编号,可以通过编号来取消定时器
// 定时器如果没有别执行,可以用clearTimeout 取消

chrome 消息队列

  • 正常
  • 延迟执行的任务列表:setTimeout

定时器问题

  • 当前代码执行过久会影响定时器任务,实时性要求高(动画)的需求不适合

    function bar() { console.log('bar') } function foo() { setTimeout(bar, 0); for (let i = 0; i < 5000; i++) { let i = 5+8+8+8 console.log(i) } } foo()

    //定时器 500ms 后执行

  • setTimeout 嵌套调用,最短间隔时间4ms

    function cb() { setTimeout(cb, 0); } setTimeout(cb, 0);

    // chrome 中 定时器嵌套调用5次以上,系统判断该函数被阻塞,系统最短间隔时间4ms

  • 未激活页面,setTimeout 执行最小间隔 1000ms

  • 延时执行时间有最大值:24.8天,超过这个时间,按照0设置

  • setTimeout 中的 this 指向全局,可以用箭头函数避免

XMLHttpRequest

xhr 问题

  1. 跨域
  2. https 混合内容

宏任务 & 微任务

宏任务:主线程-> 消息队列里的任务,通过事件循环系统执行,时间颗粒度大,执行间隔不能精确控制

  • 渲染事件(解析DOM、计算布局、绘制)
  • 用户交互事件(鼠标点击、滚动页面、放大缩小)
  • js 脚本执行事件
  • 网络请求,文档读写
  • setTimeout

微任务:异步执行的函数,在主函数执行结束后,当前宏任务结束之前

  • DOM 节点变化产生的微任务(MutationObserver 异步解决性能、微任务解决实时性)
  • Promise 产生的微任务

Promise

回调函数延迟绑定+回调函数返回值穿透->解决循环嵌套

function Bromise(executor) {
    var onResolve_ = null
    var onReject_ = null
     //模拟实现resolve和then,暂不支持rejcet
    this.then = function (onResolve, onReject) {
        onResolve_ = onResolve
    };
    function resolve(value) {
          setTimeout(()=>{
            // 实际情况 是放到微任务里
            onResolve_(value)
          },0)
    }
    executor(resolve, null);
}


// Bromise 来实现我们的业务代码
function executor(resolve, reject) {
    resolve(100)
}
//将Promise改成我们自己的Bromsie
let demo = new Bromise(executor)

function onResolve(value){
    console.log(value)
}
demo.then(onResolve)

async/await

在不阻塞主线程的情况下,用同步代码实现异步访问资源,使逻辑代码更清晰

进程 > 线程 > 协程

进程上可以有多个并行的线程,线程(cpu 调度)切换需要消耗资源

线程上可以有多个协程,但同时只能执行一个,由程序控制,不归操作系统内核管,性能提升

生成器函数(一种协程的实现形式):带*函数,yield 暂停,next恢复执行

async:通过异步执行隐式返回 Promise 作为结果的函数 = 生成器 + promise

awit:执行时创建一个Promise 对象