JS运行在浏览器中(浏览器只分配一个线程来运行JS=>JS是单线程的)
常见的异步:
=> 事件绑定
=> 定时器
=> AJAX(axios)/fetch
=> Promise中的同步异步
1.new Promise的时候,传递的executor函数一定是立即执行(同步)
2.基于then或者catch存放的方法执行是异步的
3.async/await 也是异步的;
JS是如何构建出异步变成的效果 => Event Loop 事件循环机制(Evebt Queue)
setTimeout(()=>{
console.log(1);
},50);
setTimeout(()=>{
console.log(2);
},0); //=>不是立即执行,有一个最小的反应时间;
console.time('FOR');
for(let i = 0;i<100000;i++){};
console.timeEnd('FOR'); // 循环时间<=10ms
setTimeout(()=>{
console.log(3);
},20);
console.log(4);
1.主线程自行而下加载代码,遇到异步操作放到等待任务队列中;
=>把定时器1,2放到eventQ中=>for循环(10ms)=>把定时器3放到eventQ中=>输出4;
2.主线程代码执行完,开始到Event Queue中查找(把到时间的拿出来执行:先到先执行);
2=>3=>1
所以最终输出结果 4,2,3,1
Event Queue存在两个队列
macro task queue 宏任务队列(定时器、事件绑定、ajax...) micro task queue 微任务队列(Promise、async/await...)
总的执行顺序可以理解为:同步任务=> 微任务 => 宏任务
接下来看一道面试题
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('promise1');
resolve();
}).then(function(){
console.log('promise2');
});
console.log('script end');
主栈
创建async1=>创建async2=>**输出'script start'**=>setTimeout放入宏任务=> async1()-->**输出'async1 start'**-->async2执行**输出'async2'**-->'async1 end'放入微任务=>new Promise时executor函数立即执行**输出'Promise1'**-->then里的'promise2'放入微任务=>**输出'script end'**
宏任务
=>setTimeout放入宏任务
微任务
=>'async1 end'放入微任务=>'promise2'放入微任务
主栈输出完,输出微任务(V8新版本中,promise要优于await执行(node>10.0)=>我们按照存放顺序来看)
=>'async1 end'=>'promise2'
最后输出宏任务中的
=>setTimeout
所以最终输出顺序:
=>script start=>async1 start=>async2=>Promise1=>script end =>'promise2'=>'async1 end' =>setTimeout