JS异步执行如何工作的

  • js是单线程的工作机制,不过浏览器是多线程的,所以不要担心单线程的js是不是落后,反正有浏览器帮衬。
  • 浏览器有个叫web worker的东西,可以让浏览器开出一个Worker线程,通过接受发送消息和主线程交互,并且和主线程不冲突的执行。
  • web worker的讲解详情请翻看本站其他文章讲解
  • 几乎现在的主流语言都有同步和异步问题,那么js的异步有哪些?
    • js引擎线程(解释执行js代码、用户输入、网络请求)
    • GUI线程(绘制用户界面、就是我们刚刚说的解析CSS和DOM的,它和js主线程是互斥的)
    • http网络请求线程(处理ajax的)
    • 定时触发器线程(setTimeout、setInterval)
    • 浏览器事件处理线程(将click、touch放入事件队列中)
  • 浏览器从开始执行遇到script会开启一个宏任务。遇到setTimeour也会开启一个宏任务。遇到ajax请求开启的是一个微任务。只有当一个宏任务所有的同步代码和所有微任务全部代码执行完毕后,浏览器才会开始下一个宏任务。这里的setTimeout属于下一个宏任务。
    代码举例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    console.log(1)
    setTimeout(() => {
    console.log(2)
    }, 0)
    // Promise是属于script这个宏任务的,和console.log一样都是属于Promise的
    const prom = new Promise(function (ret, rej) {
    console.log(3)
    const ajax = new XMLHttpRequest();
    ajax.onreadystatechange=function(){
    ret(4)
    }
    ajax.open("GET","https://search-merger-ms.juejin.im/v1/search?query=ajax&page=0&raw_result=false&src=web",true);
    ajax.send();
    console.log(5)
    setTimeout(() => {
    console.log(6)
    }, 0)
    })

    // prom.then()是一个微任务,所以都是属于script这个宏任务,则按照先后顺序执行
    prom.then(res => {
    console.log(res)
    setTimeout(() => {
    console.log(7)
    })
    })
    setTimeout(() => {
    console.log(8)
    })
    console.log(9)

    // 1 3 5 9 4 2 6 8 7
    ```
    - 应用举例:
    ```javascript
    /*
    需求:
    obj.eat('a') //立即打印'a'
    obj.stop(3000).eat('a') //延迟3秒后打印a
    */

    class laz {
    constructor(name) {
    this.tasks = []
    setTimeout(() => {
    this.next()
    },0)
    }
    next () {
    let task = this.tasks.shift()
    // 如果task为真,则执行task();如果task为假,则不执行task()
    task && task()
    }
    eat(val) {
    const task = (val => () => {
    console.log(val)
    this.next()
    })(val)
    this.tasks.push(task)
    return this
    }
    stop (time) {
    const task = (time => () => {
    setTimeout(() => {
    console.log(time)
    this.next()
    },time)
    })(time)
    this.tasks.push(task)
    return this
    }
    }

    const obj = new laz()
    obj.eat('a')
    obj.stop(3000).eat('a')