Js是一个单线程语言,什么是单线程,一次性只能去办一件事。这个时候如果遇到一个代码需要花很长时间,如定时器,我们是不是要等到定时器执行完成在去执行下面的代码呢,这显然是不可取了,这个时候就出现了执行栈,来存放异步的代码。等主线程把同步的代码执行完成后,在从执行栈中拿异步的代码拿到主线程中执行,这样就很好地解决了Js是单线程的问题。
一.常见的异步任务
定时器,ajax请求,Promise相关等
我们在发送一个请求的时候,需要等服务器响应过来后才去执行Then或者Catch的回调。
如:
我们平常在
按钮------>调用api方法----------->then(res)=> console.log(res)
按钮------>调用api方法----------->Catch(reject)=> console.log(reject)
这里then拿到的是成功之后的值, Catch拿到的是失败之后的值。
then和Catch是回到函数。
回调函数: 回头在去调用,这里的回头指的是服务器----------->响应---------->客户端。然后去取里面的值。这个过程很显然是一个异步的任务。因为这个过程需要服务器响应给客户端数据。需要一个等待的过程。
我们拿同步任务进行比较:
console.log(123456)
这个打印可以立马去执行。这就是一个同步任务。
定时器属于不属于异步任务呢?
setTimeout(() => {
console.log(123456);
}, 3000);
这个定时器3秒后才去打印123456。
故也放在执行栈中进行等待,等同步任务执行玩,主线程才去执行中拿出异步任务在去执行。
console.log(312);
setTimeout(() => {
console.log(123456);
}, 3000);
console.log(1);
执行的结果大家应该都知道:
312
1
123456
代码:
setTimeout(function () {
console.log(1)
}, 0);
new Promise(function executor(resolve) {
console.log(2);
for (var i = 0; i < 10000; i++) {
i == 9999 && resolve();
}
console.log(3);
}).then(function () {
console.log(4);
});
console.log(5);
代码分析:
分析
newPromise里面的任务是同步执行的。
主线程: console.log(2);
console.log(3);
console.log(5);
for循环肯定执行到9999 返回一个成功的Promise是异步的
放入执行栈:
宏:
setTimeout(function () {
console.log(1)
}, 0);
微:
resolve().then(function () {
console.log(4);
});
主线程打印 2 3 5
执行栈拿出任务 到主线程执行
微 >宏
打印 4 1
结果 2, 3, 5, 4 ,1
这里涉及到了微任务中的宏任务>微任务。
二.微任务:微>宏
常见的微任务:
Promise.all, Promise.race Ajax请求等
宏任务:
setimeout等
代码:
Promise.resolve().then(()=>{
console.log(123);
})
setTimeout(() => {
console.log(456);
}, 0);
和循序有关吗?
setTimeout(() => {
console.log(456);
}, 0);
Promise.resolve().then(() => {
console.log(123);
})
可以发现resolve()属于一个微任务。
而且定时器属于宏任务。
结论:
微任务的优先级>宏任务
三.一个长的for循环
for (var i = 0; i < 9999; i++) {
if (i == 9998) {
console.log(123);
}
}
console.log(456);
是先执行456 还是执行里面很长的123呢?
等到for循环才去执行下面代码。
结论:
for循环属于一个同步的任务。
四.习题
// #1
setTimeout(() => {
new Promise(resolve => {
resolve();
}).then(() => {
// #6
console.log('test');
});
// #5
console.log(4);
setTimeout(function () {
// #8
Promise.resolve().then(res => {
console.log(444);
})
})
Promise.resolve().then(res => {
// #7
console.log(888);
})
});
// #2
new Promise(resolve => {
resolve();
console.log(1)
}).then(() => {
// #3
console.log(3);
setTimeout(function () {
// #4
Promise.resolve().then(() => {
// #7:这一行确确实实打印了 before timeout,但是执行完毕后又产生了一个微任务
console.log('before timeout'); //#9
// return Promise.resolve(undefined)
}).then(() => {
Promise.resolve().then(() => {
// #10
console.log('also before timeout')
})
})
})
})
console.log(2);
// 第一轮:
// 主线程: //console.log(1) console.log(2);
// 执行栈: //宏:#1
// // 微:#2
// 第二轮: // 微:#3 //宏:#1 #宏4 console.log(3);
// 第三轮: // console.log(4); console.log('test'); console.log(888);
// 第四轮: //console.log('before timeout'); console.log('also before timeout')
// 第五轮: //console.log(444);
// 结果:1 2 3 4 test 888 before timeout also before timeout 444
Promise.resolve().then(() => {
Promise.resolve().then(r => {
console.log('a');
// return Promise.resolve(undefined)
}).then(r => {
console.log('h');
}).then(r => {
console.log('8');
}).then(r => {
console.log('99')
});
// return Promise.resolve(undefined)
}).then(r => {
console.log('44');
}).then(() => {
console.log('66')
}).then(() => {
console.log('7')
})
// 在执行 Promise.resolve().then的时候同时产生了两个异步任务
//如果没有返回状态这下一个默认返回一个成功的
// return Promise.resolve(undefined)
// 执行的结果: a 44 h 66 8 7 99
代码分析:
第一轮:
在执行111的时候产生两个微任务
这两个先执行第二个。
第二个又是异步 不管。
打印222
然后
打印333
执行444的时候同理
两个异步。执行第二个。
结果 111 222 333 444 555 666
输出的结果: