JS同步异步编程原理

1,007 阅读2分钟

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