当前位置: 首页 > 科技观察

AdvancedJSBasics-同步异步编程及EventLoop底层机制

时间:2023-03-16 02:00:45 科技观察

简述:JS中单线程异步编程EventLoop事件循环机制Macrotaskmacrotask[?m?kro?]Microtaskmicrotask[?ma?kro?]JS中的同步异步编程1、JS是单线程的,如何实现异步编程:1)JS是单线程的,大部分代码都是同步编程。2)在JS中,利用浏览器的多线程机制,在单线程EventLoop(事件循环机制)的基础上实现了异步的效果。2、事件循环(microtask和macrotask):1)Microtask(微任务):优先级高,可以在队列中跳转,而不是先定义先执行。包括:promise.then、async/await[generator]、requestAnimationFrame、observer、MutationObserver、setImmediate。2)宏任务(macrotask):优先级低,先定义的先执行。包括:ajax、setTimeout、setInterval、事件绑定、postMessage、MessageChannel(用于消息通信)。3.根据事件循环机制,重组流程:+先找到microtask队列,如果microtask队列中有,先从microtask队列中获取并执行,一般按入库顺序。+如果没有microtask队列,则去macrotask队列中查找。在宏任务队列中,一般先到的先执行。面试常问问题:EventLoop事件循环🌰面试题1:console.log('1')//1asyncfunctionasync1(){console.log('2')//2awaitsetTimeout(()=>{console.log('3')//8},0)console.log('4')//5}setTimeout(()=>{console.log('5')//7},0)async1()newPromise(function(resolve){console.log('6')//3resolve()}).then(function(){console.log('7')//6})console.log('8')//4//结果:12684753🌰面试题2:asyncfunctionasync1(){console.log('async1start');//2awaitasync2();console.log('async1end');//6}asyncfunctionasync2(){console.log('async2');//3}console.log('scriptstart');//1setTimeout(function(){console.log('setTimeout');//8},0)async1();newPromise(function(resolve){console.log('promise1');//4resolve();}).then(function(){console.log('promise2');//7});console.log('scriptend');//5//结果:scriptstartasync1startasync2promise1scriptendasync1endpromise2setTimeout🌰面试题3:console.log(1);//1setTimeout(()=>{console.log(2);//6Promise.resolve().then(data=>{console.log(3);//7});});newPromise((解决)=>{resolve()console.log(4)//2}).then(()=>{console.log(5);//4setTimeout(()=>{console.log(6);//8});}).then(()=>console.log(7))//5console.log(8);//3//结果:1,4,8,5,7,2,3,61,4,8是同步的5,7是microtasks2macrotasks3microtasks6macrotasksprocess/thread*Coreanswer|需要巩固的基础知识1)一个进程代表一个程序(浏览器打开一个页卡(Tabpage))就是一个进程);2)线程是用来处理进程中特定的事情的,如果一个程序需要同时做很多事情,就需要开辟很多线程;3)一个线程在同一时间只能做一件事;官方1)进程是cpu资源分配的最小单位(可以拥有资源并独立运行的最小单位)2)线程是cpu调度的最小单位(线程是基于进程的程序运行单位,a进程中可以有多个线程)。浏览器是多线程的*核心答案|需要巩固的基础知识1)浏览器是多进程的;2)浏览器之所以能够运行,是因为系统为其进程分配了资源(cpu、内存);3)简单理解,每打开一个Tab页,就相当于创建了一个独立的浏览器进程;然后看看它包含了哪些线程(列出一些主要常驻线程)GUI渲染线程1)负责渲染浏览器界面,解析HTML、CSS,构建DOM树和RenderObject树,布局绘制等2)当界面需要待重绘(Repaint)或回流(reflow)被某些操作触发时,这个线程就会执行。3)注意GUI渲染线程和JS引擎线程是互斥的。当JS引擎执行时,GUI线程会被挂起(相当于被冻结),GUI更新会保存在一个队列中,等待JS引擎空闲。被执行。JS引擎线程也称为JS内核,负责处理Javascript脚本程序。(如V8引擎)1)JS引擎线程负责解析Javascript脚本并运行代码。2)JS引擎一直等待任务队列中任务的到来,然后进行处理。任何时候一个Tab页(renderer进程)中只有一个JS线程在运行JS程序。3)还要注意GUI渲染线程和JS引擎线程是互斥的,所以如果JS的执行时间过长,会导致页面渲染不连贯,导致页面渲染加载阻塞。JS*中的单线程异步编程核心答案|基础知识需要巩固。JS是单线程的:浏览器只分配一个线程来渲染JS代码。1、JS中大部分代码都是“同步编程”:上面的任务没有处理完,下面的任务也处理不了。2.但是在JS中利用浏览器的多线程机制,可以规划出“异步编程”的效果。定时器ajax/Fetch/跨域(HTTP网络请求)事件绑定Promise也有异步编程Generator/yieldasync/await计算程序执行时间(预估)1)运行监控console.time/timeEnd(受当前电脑影响)运行环境)2)BigOnotation(提前预测)console.time('AAA');for(leti=0;i<99999999;i++){}console.timeEnd('AAA');实际项目应该避免死循环(重要)while(true){}console.log('OK');//不要执行:上述死循环一直占用这个“JS渲染线程”,如果线程不空闲,不能处理其他定时器的异步编程1)设置定时器任务为同步2)“间隔这么长,执行定时器绑定的函数”这个任务是异步的3)遇到异步任务时,浏览器不会等它执行完,会继续渲染下面的代码;当执行下面的代码,时间达到执行条件时,异步任务就会被执行;setTimeout(()=>{console.log("OK");//2},1000);console.log('NO');//设置1interval为0不代表立即执行,但是浏览器有“最快responsetime(Google:5~6msIE:13~17ms)”,设置为0,最快需要等到5~6ms左右setTimeout(()=>{console.log('OK');//2},0);console.log('否');//1🌰异步编程示例一:setTimeout(()=>{console.log(1);},20);console.log(2);setTimeout(()=>{console.log(3);},10);console.log(4);console.time('AA');for(leti=0;i<90000000;i++){//dosoming}console.timeEnd('AA');//=>AA:大约79msconsole.log(5);设置超时(()=>{console.log(6);},8);console.log(7);setTimeout(()=>{console.log(8);},15);console.log(9);//Result:2,4,5,7,9,3,1,6,8绘图分析:(有图有真相)执行顺序:同步任务->微任务->宏任务(微任务,宏该任务在EventQueue)的详细信息中。当“同步任务”或栈中的其他任务未执行时,JS渲染线程不会空闲。即使定时器到了指定的时间,也不会执行。"JS是单线程的,一次只能做一件事"=>定时器设置的等待时间是触发执行的最快时间,很多时候时间到了也不一定执行,只有在JS渲染线程空闲的时候才会执行。