事件循环机制

javascript 事件循环机制

1. javascript 是单线程

javascript 是单线程的执行方式,但这其中会存在一些问题,就是如果当一个语句也需要执行很长时间的话,比如请求数据、定时器等后面的语句就得一直等着前面的语句执行结束后才会开始执行,显然这是不可取的。所以 javascript 将所有执行任务分为了同步任务和异步任务

2. 同步任务和异步任务

同步任务的执行,其实就是跟前面那个案例一样,按照代码顺序和调用顺序,支持进入调用栈中并执行,执行结束后就移除调用栈。

而异步任务的执行,首先它依旧会进入调用栈中,然后发起调用,然后解释器会将其响应回调任务放入一个任务队列,紧接着调用栈会将这个任务移除。当主线程清空后,即所有同步任务结束后,解释器会读取任务队列,并依次将已完成的异步任务加入调用栈中并执行。

3. 宏任务和微任务

在任务队列中,其实还分为宏任务队列微任务队列,对应的里面存放的就是宏任务微任务宏任务和微任务都是异步任务

==宏任务队列主要有:ajax、setTimeout、setInterval、DOM 监听 等==

==微任务队列主要有:Promise 的 then 回调、 Mutation Observer API、queueMicrotask( ) 等==

4. javascript 代码的执行顺序

javascript 开始从上到下依次执行, 遇到微任务将微任务加入到微任务队列,遇到宏任务将宏任务加入到宏任务队列,所有的同步任务都执行结束开始顺序执行微任务队列,微任务队列执行完毕开始执行宏任务队列的第一个任务,宏任务队列的第一个任务执行完毕,如果微任务队列有任务则顺序执行微任务队列直到微任务队列清空,没有任务则继续执行下一个宏任务,==宏任务执行之前,必须保证微任务队列是空的==,如此反复,直到宏任务队列和微任务队列都没有任务则结束。

练习题

1. 题一

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
setTimeout(function () {
console.log("setTimeout1");
new Promise(function (resolve) {
resolve();
}).then(function () {
new Promise(function (resolve) {
resolve();
}).then(function () {
console.log("then4");
});
console.log("then2");
});
});

new Promise(function (resolve) {
console.log("promise1");
resolve();
}).then(function () {
console.log("then1");
});

setTimeout(function () {
console.log("setTimeout2");
});

console.log(2);

queueMicrotask(() => {
console.log("queueMicrotask1");
});

new Promise(function (resolve) {
resolve();
}).then(function () {
console.log("then3");
});

/*
promise1
2
then1
queueMicrotask1
then3
setTimeout1
then4
then2
setTimeout2
*/

2. 题二

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
setTimeout(function () {
console.log("1");
});
new Promise(function (resolve) {
console.log("2");
resolve();
}).then(function () {
console.log("3");
});
console.log("4");
new Promise(function (resolve) {
console.log("5");
resolve();
}).then(function () {
console.log("6");
});
setTimeout(function () {
console.log("7");
});
function bar() {
console.log("8");
foo();
}
function foo() {
console.log("9");
}
console.log("10");
bar();

// 2 4 5 10 8 9 3 6 1 7

3. 题三

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
setTimeout(() => {
console.log("1");
new Promise(function (resolve, reject) {
console.log("2");
setTimeout(() => {
console.log("3");
}, 0);
resolve();
}).then(function () {
console.log("4");
});
}, 0);
console.log("5");
setTimeout(() => {
console.log("6");
}, 0);
new Promise(function (resolve, reject) {
console.log("7");
// reject();
resolve();
}).then(function () {
console.log("8");
});
console.log("10");

// 5 7 10 8 1 2 4 6 3

4. 题四

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
}
async function async2() {
console.log("async2");
}
async1();
console.log("script start");

// async1 start
// async2
// script start
// async1 end

5. 题五

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
async function async1() {
console.log("async1 start");
await async2();
console.log("async1 end");
}

async function async2() {
console.log("async2");
}

console.log("script start");

setTimeout(function () {
console.log("setTimeout");
}, 0);

async1();

new Promise(function (resolve) {
console.log("promise1");
resolve();
}).then(function () {
console.log("promise2");
});

console.log("script end");

/*
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
*/