# 1.浏览器的事件循环
- 为什么 js 在浏览器中有事件循环 ?
JS 是 单线程的
event loop
- 二种任务?
宏任务 整体代码
settimeout
setInterval
微任务 new Promise().then()
await
- 为什么要引入微任务的概念,只有宏任务不行吗?
宏任务执行先进先出
的原则,需要有机制优先执行
微任务;
执行一个宏任务后,执行全部
的微任务队列
。然后再下一轮
宏任务。
- 题目
async function async1() {
console.log('async1 log'); // 2. 同步代码直接执行
await async2(); // 执行async2方法,::tips await 后的代码 在 await 执行方法后,相当于又新建了一个微任务
console.log('async2 log'); // 6. 执行第一个微任务 ::tips 推向微任务队列 排序1 需要同步代码执行完毕再执行
}
async function async2() {
console.log('async2'); // 3. 同步代码直接执行
}
console.log('script start'); // 1. 同步代码最先执行
setTimeout(function () { // 宏任务 推向宏任务队列
console.log('setTimeout'); // 8. 执行 宏任务队列 代码运行完毕
}, 0);
async1(); // 执行 async1 方法
new Promise(function (res) { // 遇到new Promise 方法 立即执行
console.log('promise1'); // 4. 同步代码直接执行
res();
}).then(function () { // then 推向微任务队列 排序2
console.log('promise2'); // 7. 执行第二个微任务 微任务执行完毕,执行宏任务队列
});
console.log('script end'); // 5. 同步代码直接执行 同步代码执行完毕,按照 先进先出 先执行微任务队列
script start
async1 log
async2
promise1
script end
async2 log
promise2
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
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
- 题目
console.log('start'); // 1. 同步代码 直接执行
// 宏任务 推向宏任务队列 排序1
setTimeout(() => {
console.log('children2'); // 3. 执行第一个 宏任务代码 同步代码 直接输出
// promise 执行完毕,then 推向 微任务队列 排序1 此时第一个宏任务代码执行完毕,执行微任务队列
Promise.resolve().then(() => {
console.log('children3'); // 4. 执行微任务 同步代码 直接输出 此时微任务 只有一个,执行完毕,继续执行下一个宏任务代码
}, 0);
});
// new Promise 的执行体,相当于同步代码,读到就要执行
new Promise(function(resolve, reject) {
console.log('children4'); // 2. 同步代码直接输出
// 宏任务 推向宏任务队列 排序2
setTimeout(function() {
console.log('children5'); // 5. 执行第二个宏任务代码 同步代码 直接输出
resolve('children6'); // promise 成功 将then 里的代码 推向 微任务队列 排序 1,宏任务执行完毕,执行微任务代码。::tips 这里排序1 是因为上一个微任务已经全部执行完毕了。
}, 0);
}).then((res) => {
console.log('children7'); // 6. 执行微任务代码,同步代码 直接输出
// 宏任务 推向宏任务队列 排序1, 微任务执行完毕。 ::tips 因为宏任务队列现在是空的,所以排序是1
setTimeout(() => {
console.log(res); // 7. 微任务已无任务执行,执行宏任务代码 同步代码 直接输出
}, 0);
});
start;
children4;
children2;
children3;
children5;
children7;
children6;
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
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
- 题目
// 定义p方法,未执行,不用看
const p = function() {
return new Promise((resolve, reject) => {
// 定义p方法,未执行,不用看
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
// 宏任务 推向宏任务队列 排序1
resolve(1); // 执行 第一个宏任务,但是此时的 promise状态,已经是 resolve 状态,因为promise的状态值一旦成功,或者失败,就不允许修改,所以这一行执行无效。
}, 0);
resolve(2); // promise 成功 直接 看p1的 then
});
p1.then((res) => {
// p1 成功。把then的代码 推到微任务队列 排序1
console.log(res); // 3. 执行第一个微任务 res 为2,第一个微任务执行完毕,执行第二个微任务
});
console.log(3); // 1. 同步代码直接执行
resolve(4); // 当前返回的promise 成功 把p的then 推到微任务队列 排序2
});
};
p().then((res) => {
// 执行p方法
console.log(res); // 4. 第二个微任务,res为 4 微任务执行完毕,执行下一轮的宏任务
});
console.log('end'); // 2. 同步代码 直接执行,同步代码执行完毕,执行微任务队列排序1
3;
end;
2;
4;
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
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
# 2. 手写一个 promise.all 的方法;
function promiseAll(val) {
return new Promise((resolve, reject) => {
if (!Array.isArray(val)) {
reject(new Error('必须是个数组'));
}
let promiseLen = val.length;
let arr = [];
let count = 0;
for (let i = 0; i < promiseLen; i++) {
Promise.resolve(val[i])
.then((res) => {
arr[i] = res; // 这里不用push。而是用索引,是为了 对应参数。不是所有的方法执行时间都是一样的。
count++;
if (count === promiseLen) {
resolve(arr);
}
})
.catch((e) => reject(e));
}
});
}
let pro1 = new Promise((resolve) => {
setTimeout(() => {
resolve(1);
}, 1000);
});
let pro2 = new Promise((resolve) => {
setTimeout(() => {
resolve(2);
}, 2000);
});
let pro3 = new Promise((resolve) => {
setTimeout(() => {
resolve(3);
}, 3000);
});
promiseAll([pro1, pro2, pro3]).then((res) => {
console.log(res);
});
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
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
# 3. 算法 接雨水
function operation(arr) {
let arrLen = arr.length;
let num = 0;
for (let i = 1; i < arrLen - 1; i++) {
let l_max = 0;
let r_max = 0;
for (let j = i; j < arrLen; j++) {
r_max = Math.max(r_max, arr[j]);
}
for (let j = i; j > 0; j--) {
l_max = Math.max(l_max, arr[j]);
}
num += Math.min(r_max, l_max) - arr[i];
}
return num;
}
function operation(val) {
let len = val.length;
let count = 0;
let l_max = new Array(len);
let r_max = new Array(len);
l_max[0] = val[0];
r_max[len - 1] = val[len - 1];
// 查找自身 左侧的最大值
for (let i = 1; i < len; i++) {
l_max[i] = Math.max(val[i], l_max[i - 1]);
}
// 查找自身 右侧的最大值
for (let i = len - 2; i >= 0; i--) {
r_max[i] = Math.max(val[i], r_max[i + 1]);
}
for (let i = 0; i < len - 1; i++) {
count += Math.min(l_max[i], r_max[i]) - val[i];
}
return count;
}
console.log(operation([0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 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
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
# 4. 前端加载优化
做性能优化的目的是什么?
首屏时间
首次可交互时间
首次有意义内容渲染时间
只请求当前需要的资源 异步加载,懒加载,polyfill
缩减资源体积 打包压缩文件 webpack gzip 图片格式的优化,压缩。webp 尽量控制cookie的大小 因为每次请求都会携带cookie
时序优化 js promise.all 并发执行请求
合理的利用缓存 cdn