异步&事件环
一.Promise.all原理
// 判断是否是promise
const isPromise = value =>{
if((typeof value === 'object' && value !== null) ||typeof value === 'function'){
return typeof value.then === 'function'
}
return false;
}
Promise.all = function (promises) {
return new Promise((resolve,reject)=>{
let arr = [];
let i = 0;
let processData = (index,data)=>{
arr[index] = data; // 保证返回结果顺序
if(++i === promises.length){
resolve(arr);
}
}
for(let i = 0; i< promises.length;i++){
let current = promises[i];
if(isPromise(current)){
current.then(data=>{
processData(i,data)
},reject)
}else{
processData(i,current);
}
}
})
}
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
Promise.all可以解决异步并发问题,并且返回的结果按照调用的顺序进行存储。全部成功后才成功否则执行失败逻辑
二.Promise.race原理
1.实现原理
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
// 谁返回的结果最快 就用谁的
for (let i = 0; i < promises.length; i++) {
let current = promises[i];
if (isPromise(current)) {
current.then(resolve, reject)
} else {
resolve(current);
}
}
})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
race只采用第一个成功或者失败的结果
2.应用场景
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功');
}, 3000);
})
function wrap(p){
let abort;
let p1 = new Promise((resolve,reject)=>{
abort = reject;
});
let newPromise = Promise.race([p1,p])
newPromise.abort = abort
return newPromise
}
let p1 = wrap(p);
p1.then(data => {
console.log('success', data)
}, err => {
console.log('error', err)
})
setTimeout(() => {
p1.abort('超过2s了');
}, 2000);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
借助race的特点,可以实现立即中断promise变为失败态。常用作超时操作
三.promisify原理
function promisify(fn){
return function (...args) {
return new Promise((resolve,reject)=>{
fn(...args,function (err,data) {
if(err) reject();
resolve(data);
})
});
}
}
let read = promisify(fs.readFile);
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
我们可以快速的将node的
api方法转化成promise,核心原理就是借助了error-first的特性。在内部手动处理错误
四.generator使用
1.遍历器的基本实现
const interable = { 0: 'a', 1: 'b', 2: 'c', length: 3 };
interable[Symbol.iterator] = function() {
let index = 0;
return { // 遍历器对象
next: () => {
return { value: this[index], done: index++ == this.length }
}
}
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
如果我们自己去迭代一个对象需要实现一个迭代器接口,自己返回一个具有next方法的对象。内部会调用这个next方法返回结果包含value和done,当done为true时迭代完成。
2.通过生成器实现
const iterable = { 0: 'a', 1: 'b', 2: 'c', length: 3 };
iterable[Symbol.iterator] = function*() {
let index = 0;
while (index !== this.length) {
yield this[index++]
}
}
console.log([...iterable]);
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
3.生成器使用
function * read(){ // 感觉写代码就是同步的写,但是执行还是异步嵌套的执行
let content = yield fs.readFile('./name.txt','utf8'); // 1
let age = yield fs.readFile(content,'utf8'); // 2
return age;
}
1
2
3
4
5
2
3
4
5
五.co库原理
function co(it){
return new Promise((resolve,reject)=>{
function next(data){
let {value,done} = it.next(data);
if(!done){
Promise.resolve(value).then(data=>{
next(data);
},reject)
}else{
resolve(value);
}
}
next();
});
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
这里我们主是掌握思想,异步迭代的思想。(产生一个迭代函数,当做回调函数使用)
六.浏览器事件环
1.浏览器的进程
每一个页卡都是进程 (互不影响)
浏览器也有一个主进程 (用户界面)
渲染进程 每个页卡里 都有一个渲染进程 (浏览器内核)
网络进程 (处理请求)
GPU进程3d绘制第三方插件的进程
2. 渲染进程(包含着多个线程)
GUI渲染线程 (渲染页面的)
js引擎线程 他和页面渲染时互斥事件触发线程 独立的线程
EventLoop事件
click、setTimeout、ajax也是一个独立线程

3.宏任务,微任务
宏任务 宿主环境提供的异步方法 都是宏任务
scriptui渲染微任务 语言标准提供
promisemutationObserver
4.微任务和GUI渲染
<script>
document.body.style.background = 'red';
console.log(1)
Promise.resolve().then(()=>{
console.log(2)
document.body.style.background = 'yellow';
})
console.log(3);
</script>
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
5.事件任务
<script>
button.addEventListener('click',()=>{
console.log('listener1');
Promise.resolve().then(()=>console.log('micro task1'))
})
button.addEventListener('click',()=>{
console.log('listener2');
Promise.resolve().then(()=>console.log('micro task2'))
})
button.click(); // click1() click2()
</script>
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
6.定时器任务
<script>
Promise.resolve().then(() => {
console.log('Promise1')
setTimeout(() => {
console.log('setTimeout2')
}, 0);
})
setTimeout(() => {
console.log('setTimeout1');
Promise.resolve().then(() => {
console.log('Promise2')
})
}, 0);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
7.任务执行面试题
console.log(1);
async function async () {
console.log(2);
await console.log(3);
console.log(4)
}
setTimeout(() => {
console.log(5);
}, 0);
const promise = new Promise((resolve, reject) => {
console.log(6);
resolve(7)
})
promise.then(res => {
console.log(res)
})
async ();
console.log(8);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
掌握Vue中nextTick原理