概念
同步
: 在一个线程上(主栈/主任务队列)同一个时间只能做一件事情,当前事情完成后才能进行下一个事情(先把一个任务进栈执行,执行完成,再把下一个任务进栈,上一个任务出栈)
异步
:在主栈中执行一个任务,但是发现这个任务是一个异步的操作,会把它移除主栈,放到等待任务队列中(此时浏览器会分配其他线程监听异步任务是否到达指定的执行时间),如果主栈执行完成,监听者会把到达时间的异步任务重新放到主栈中执行…
常见异步:
[宏任务: macro task]
- 定时器
- 事件绑定
- ajax
- 回调函数
[微任务:micro task]
- Promise(async/await)
- process.nextTick
- Node中的fs可以进行异步的I/O操作
执行顺序 SYNC -> micro -> macro
setTimeout
//1
setTimeout(() => {
console.log(1);
}, 20);
//2
setTimeout(() => {
console.log(2);
}, 0);
console.time('W');
let i = 0;
while(i < 99999999){
i++;
}
console.timeEnd('W');
setTimeout(() => {
//3
console.log(3);
}, 10);
//4
console.log(4)
执行过程:
程序自上而下执行,将前两个异步任务放进等待队列,然后进入while循环,执行了500多ms,此时前两个异步任务已经到达时间,而且2在1前,(注意setTimeout里的时间为最小等待时间)。之后把3加入等待任务队列,遇到4输出。
最后输出4 2 1 3
因此更加能够体会到:setTimeout里面的时间,其实是将函数放入等待队列的时候开始计算的。
如果将99999999变为10呢?那毫无疑问,应该是4 3 2 1
Ajax
let xhr = new XMLHttpRequest();
xhr.open('get', 'xxx.txt');
xhr.send();
/*放等待任务队列之前状态是1*/
xhr.onreadystatechange = () => {
console.log(xhr.readyState);
}
/*主栈空闲了*/
//状态为2 执行函数
//状态为3 执行函数
//状态为4 执行函数
Promise
console.log(1);
//Promise本身的Excutor为同步执行
new Promise((resolve, reject) => {
console.log(2);
setTimeout(() => {
resolve()//Promise内部机制:执行resolve会把之前基于then存放的方法执行
}, 10);
}).then(() => {console.log(3)});
console.log(4);
//1 2 4 3
async / await
function AA() {
return new Promise((resolve, reject) => {
setTimeout(() => {
Math.random() < 0.5 ? reject(100): resolve(200);
})
})
}
async function fn() {
console.log(2);
let res = await AA();
/*
* 1.先把AA执行,返回一个Promise实例
* 2.它会暂时跳出当前正在执行的函数,将后面的代码放到等待队列
* 3.主栈暂时空闲
* 4.当主栈的其他任务完成,并且AA中的Promise也已经计算完成最后的结果,再把之前的第二步放到等待队列的内容,拿回主栈执行
*/
console.log(3);
}
fn();
console.log(4);
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('resolve1');
resolve();
}).then(function() {
console.log('promise2');
})
console.log('script end');
//script start
//async1 start
//async2
//resolve1
//script end
//promise2
//setTimeout
process
//=>process.nextTick
process.nextTick(()=>{})
//把当前任务放到主栈最后执行
//当主栈执行完,先执行nextTick
//=>process.env.NODE_ENV:全局环境变量
//用途:区分不同环境的不同操作,开发环境、测试环境、生产环境。
let ENV = process.env.NODE_ENV;
if(ENV === 'dev'){
console.log('我是开发环境');
}
if(ENV === 'pro') {
console.log('我是生产环境');
}
if(ENV === 'test'){
console.log('我是测试环境');
}