一、前言

JavaScript是单线程语言,也就是说,只有一条通道,且js中任务是按顺序依次执行的,但若有一个任务时间过长,就会让后续任务一直等待。为了解决这个问题,将任务分为同步任务和异步任务,异步任务又分为宏任务和微任务。

 

二、同步任务和异步任务

1、同步任务

        又叫做非耗时任务,指的是在主线程排队执行的任务。只有前一个任务执行完毕,后一个才可执行。

2、异步任务

        又叫做耗时任务,异步任务由JavaScript委托给宿主环境进行执行。

3、执行过程

1)同步任务由JavaScript主线程依次执行,异步任务委托给宿主环境执行

2)已完成的异步任务对应的回调函数加入到任务队列中等待执行

3)JavaScript主线程中被清空后,读取任务队列的回调函数,依次执行

4)JavaScript主线程不断重复以上几步。这个过程是循环不断的,所以这种运行机制被称为EventLoop(事件循环)

三、宏任务和微任务

1、宏任务和微任务有哪些

宏任务:异步Ajax请求,setTimeout,setInterval,文件操作,new Promise等

微任务:Promise.then,Promise.catch,Promise.finally,process.nextTick等

2、宏任务和微任务的执行过程

        先执行同步代码,遇到异步宏任务将其放入宏任务队列中,遇到异步微任务将其放入微任务队列中,当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行,微任务执行完毕后再将异步宏任务从队列中调入主线程执行,一直循环至所有任务执行完毕。

四、setTimeout()到底是异步的还是同步的

首先,让我们执行这样一段代码:

console.log('111');
setTimeout(()=>{
    console.log('222')
},1000);
console.log('333');
setTimeout(()=>{
    console.log('444')
},0);
console.log(555);

打印结果为:

         可以看出,setTimeout并没有阻塞主线程,所以不是同步执行。第二个setTimeout虽然时间为0,但是仍然在1、3、5之后执行的,所以也明显不是异步。

        任务队列除了放置异步任务,也可以放置定时事件。setTimeout()是将事件插入了任务队列,必须等当前代码(执行栈)执行完,主线程才会去执行它指定的回调函数。

        综上所述,setTimeout类似异步,但不是异步。

异步的三种实现方式:

1)回调函数(回调函数不一定是异步,但异步一定有回调函数)

2)事件

3)promise对象

五、任务的执行过程实例详解

console.log('1');

setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})
process.nextTick(function() {
    console.log('6');
})
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})
setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})

1)执行第一行的同步任务,打印1

2)第一个setTimeout加入任务队列宏任务区,记为s1

3)第15行的process.nextTick是异步任务中的微任务,加入微任务区,记为n1

4)第18行的promise是同步任务,打印7,其后的.then是微任务,加入微任务区,记为t1

5)第24行的setTimeout加入任务队列宏任务区,记为s2。至此,同步代码执行完毕。

6)执行微任务区中的任务,n1打印6,t1打印8。至此,微任务区任务执行完成

7)执行宏任务区s1,打印2,其内process.nextTick放入微任务区,记为n2,其后promise为同步任务,立即执行打印4,将后续.then微任务放入微任务区记为t2

8)继续执行微任务区,n2打印3,t2打印5

9)执行第二个setTimeout,直接打印9,其内process.nextTick放入微任务区,记为n3,其后promise为同步任务,立即执行打印11,将后续.then微任务放入微任务区记为t3

10)执行微任务,n3打印10,t3打印12

最终打印结果为:1、7、6、8、2、4、3、5、9、11、10、12

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐