js中的同步异步编程
> 浏览器是多线程的,JS是单线程的(浏览器之分配一个线程来执行JS)
> 进程大线程小: 一个进程中包含多个线程,例如在浏览器中打开一个HTML页面就占用了一个进程,加载页面的时候,浏览器分配一个西线程去计算DOM树,分配其他的线程去加载对应得资源文件...在分配一个线程去自上而下执行JS
同步编程: 在一个线程上(主栈/主任务队列),同一个时间只能做一件事情,当前事情完成才能进行下一个事情(先把一个任务进栈执行,执行完出栈,在把下一个任务进栈...)
异步编程:在主栈中执行一个任务,但是发现这个任务是一个异步得操作,我们会把它移除主栈,放到等待栈任务队列中(此时浏览器会分配其他线程监听异步任务是否到达指定的执行时间),如果主栈任务执行完成,监听者会把到达时间的异步任务重新放到主栈中执行...
异步任务:
[宏任务]: macro task
- 定时器
- 事件绑定
- ajax
- 回调函数
- node中fs可以进行异步得I/O操作
[微任务]: micro task
- Promise(async/await)
Promise并不是完全的同步,当再Excutor中执行resolve或者reject的时候,此时的异步操作,会执行then/catch等。当主栈完成后,才会去调用resove/reject吧存放的方法执行
- process.nextTick
执行顺序优先级
SYNC => MICRO(微任务) => MACRO(宏任务)
所以JS中的异步编程仅仅是根据某些机制来管控任务的执行顺序,不存在同时执行两个任务这一说法。
定时器
setTimeout(()=>{console.log(1)},20)
setTimeout(()=>{console.log(2)},0) //=>默认会有最小的等待时间(v8一般是5-6MS)
console.time('WHILE')
let i = 0;
while(i<=10){i++}
console.timeEnd('WHILE')
setTimeout(()=>{console.log(3)},10)
console.log(4)
// 4 2 1 3
解析:
![](https://img.haomeiwen.com/i8492420/cd4bd3119da0b434.png)
AJAX
// => AJAX任务开始: SEND
// => AJAX任务结束: 状态为4
let xhr = new XMLHttpRequest();
xhr.open('GET','xxx.text',false);
/*放到等待去的时候,此时状态是1*/
xhr.onreadystatechange=()=>{
console.log(xhr.readyState) //=>4
}
xhr.send();
/* 状态为4的时候,主栈空闲 */
let xhr = new XMLHttpRequest();
xhr.open('GET','xxx.text',false);
xhr.send();
/* 状态已经为4了 */
xhr.onreadystatechange=()=>{ //状态改变才会出发,放到等待区的时候状态已经为4了,不会再改变了,所以不会再执行这个方法了(啥都不会输出)
console.log(xhr.readyState)
}
let xhr = new XMLHttpRequest();
xhr.open('GET','xxx.text');
xhr.send(); //=》异步操作,执行send后,有一个线程是去请求数据,主栈会空闲下来
/*放等待区之前状态是1*/
xhr.onreadystatechange=()=>{
console.log(xhr.readyState) //2 3 4
}
/*主栈有空闲了*/
// 状态为2,把函数执行
// 状态为3,把函数执行
// 状态为4,把函数执行
Promise
/*
console.log(1)
new Promise((resolve,reject)=>{
// => new Promise的时候会立即吧excutor函数(也就是传递的回调函数)执行,所以Promise本身可以理解为同步的
console.log(2);
resolve(); //Promise内部机制,执行resolve会把之前基于then存放的方法执行
}).then(()=>{ //执行完成excutor,紧接着执行then,执行then方法,会把传递的回调函数放到指定的容器中,等待出发执行(Promise内部机制)
console.log(3)
})
console.log(4)
*/
console.log(1)
new Promise((resolve,reject)=>{
console.log(2);
resolve();
}).then(()=>{
console.log(3)
})
console.log(4)
async-await
// ES7中新增加对Promise操作的新语法,async/await(使用await必须保证当前方法是基于async修饰的)
/*
function AA(){
return new Promise((resolve,reject)=>{
setTimeout(()=>{
Math.random()<0.5?reject(100):resolve(200)
},0)
})
}
fn()
console.log(1)
async function fn(){
console.log(2)
let res = await AA(); //先把AA执行。等待AA中的PROMISE完成(不论成功和失败),都会把最后的处理结果获取到赋值给RES,拿到后在执行后面的代码(有人说:AWAIT把是异步的操作同步化)
console.log(res)
console.log(3)
}
console.log(4)
// fn()
*/
function AA(){
console.log(1)
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(200)
},0)
})
}
async function fn(){
console.log(2)
let res = await AA();
await执行的原理
/*
1.先把AA执行,返回一个Promise实例
2.它会暂时跳出当前正在执行的函数(Fn),也就是await后面的代码暂时先不执行(把后面的代码从主栈中移除,放到等待区中)
3.主栈暂时空闲
4.当主栈中的其他任务执行完成(主栈空闲),并且AA中的PROMISE也已经计算完成最后的结果,再把之前的第二步移到等待区的内容,重新那回到主栈中执行
*/
console.log(3)
}
fn()
console.log(4)
// while(true){
// }
// => 2 1 4 3 AWAIT并不是同步
// 面试题(涉及到宏任务与微任务)
async function async1(){
console.log('async1 start')
await async2(); //先执行async2(),在等待
console.log('async1 end')
}
async function async2(){
console.log('async2')
}
console.log('script start')
setTimeout(()=>{
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”(根据不同的V8版本,是不一样的) “setTimeout”
网友评论