最近在检讨,不少知识都是只会用,不理解底层的知识。因此在开发过程当中遇到一些奇怪的比较难解决的bug,在思考的时候就会收到限制。因此,在这里一点一点补充基础知识吧。前端
好啦,下面进入正题面试
技术的出现,都跟现实世界里的场景密切相关。一样的,咱们就结合现实场景,来回答这三个问题。ajax
(1)js为何是单线程的?
js是一种脚本语言,脚本语言是为了缩短传统的编写-编译-连接-运行过程而建立的计算机编程语言,脚本语言不须要编译,能够直接用,由解释器来负责解释。
js最初被设计用在浏览器中,那么想象一下,若是浏览器中的js是多线程的。。。
场景描述:
如今有两个进程:process1和process2,因为是多线程的js,因此它们对同一个DOM同时进行操做process1删除了该DOM,而process2编辑了该DOM,同时下达了两个矛盾的命令,你这让浏览器怎么执行呢?
这样一想,是否是就理解了js为何被设计成单线程了吧~~~编程
(2)js为何是异步的?
场景描述:
若是js不存在异步,只能自上而下执行,若是上一行执行时间很长,好比说没有网了,那么下面的代码就会被阻塞,对于用户来讲,阻塞就意味着“卡死”,这样致使用户体验不好。因为这个“缺陷”,致使JavaScript的全部网络操做,浏览器事件,都必须是异步执行。
因此,js是存在异步执行的,好比setTimeout、setInterval、ajax、promisepromise
(3)单线程是怎么实现异步的?
场景描述:
经过Event Loop(事件循环),因此说,理解了Event Loop机制,也就理解了js的执行机制啦。浏览器
举个栗子:观察下它的执行机制网络
console.log(1) setTimeout(function(){ console.log(2) },0); console.log(3)
毫无疑问:运行结果是1 3 2多线程
也就是说:setTimeout里的函数并无当即执行,而是延迟了一段时间,知足必定条件后才去执行的,咱们叫作异步代码。异步
因此这里咱们首先知道了js里的一种分类方式,就是将任务分为:同步任务和异步任务。编程语言
按照这种分类方式:js的执行机制是
以上三步循环执行,这就是Event Loop
因此上面的栗子,你是否能够描述它的执行顺序了呢?
console.log(1) //是同步任务,放进主进程里 setTimeout(function(){ //是异步任务,放进event table,0s以后被推入event queue里 console.log(2) },0); console.log(3) //是同步任务,放进主进程里 //当一、3在浏览器控制台被打印后,主线程去event queue中查看是否有可执行的函数,执行setTimeout里的函数。
因此,上面关于Event Loop就是我对js执行机制的理解,是否是很简单呢。。。。
慢着!看看下面的这段代码
又一个栗子:
setTimeout(function(){ console.log("定时器开始啦~~~"); }) new Promise(function(resolve){ console.log("立刻执行for循环啦"); for(var i=0;i<10000;i++){ i==99&&resolve(); } }).then(function(){ console.log("执行then函数啦") }); console.log("表演完毕!");
有没有很熟悉,好像面试过程当中常常遇见这种问题呀~~~
如今,咱们按照上面学到的js执行机制去分析一下下
setTimeout(function(){ //是异步任务,被放进event table中 console.log("定时器开始啦~~~"); }) new Promise(function(resolve){ //是同步任务,被放进主进程中,直接执行 console.log("立刻执行for循环啦"); for(var i=0;i<10000;i++){ i==99&&resolve(); } }).then(function(){ //是异步任务,被放进event table中 console.log("执行then函数啦") }); console.log("表演完毕!"); //是同步任务,被放进主进程中,直接执行
运行结果是:【立刻执行for循环啦----表演完毕!----执行then函数啦----定时器开始啦~~~】
那么,难道是异步任务的执行顺序不是先后顺序,而是另有规定?事实上,按照同步和异步的划分方式,并不许确。
因此这里咱们首先知道了js里的一种分类方式,就是将任务分为:同步任务和异步任务。
叨叨了半天,原来都是一些“假大空”的东西,搞什么搞嘛,哼!!!
准确的划分方式是:
按照这种分类方式:js的执行机制就是
执行一个宏任务,执行过程当中若是遇到微任务,就将其放在微任务的event queue里
当前宏任务执行完成后,会查看微任务的event queue,并将里面的所有微任务依次执行完。
重复以上两个步骤,结合Event Loop第一课和Event Loop第二课,就是更为准确的js执行机制了。
尝试按照刚才学到的执行机制,去分析第二个栗子:
setTimeout(function(){ console.log("定时器开始啦~~~"); }) new Promise(function(resolve){ console.log("立刻执行for循环啦"); for(var i=0;i<10000;i++){ i==99&&resolve(); } }).then(function(){ console.log("执行then函数啦") }); console.log("表演完毕!"); //首先执行script中的宏任务; //遇到setTimeout,放进宏任务的event queue中; //遇到new Promise直接执行,打印“立刻执行for循环啦”; //遇到then方法,是微任务,被放进微任务的event queue //执行打印“表演完毕!”,本轮宏任务执行完毕; //查看本轮微任务,发现then方法里的函数,执行打印“执行then函数啦” //到此,本轮Event Loop所有完成 //下一轮循环里,先执行一个宏任务,发现宏任务的event queue中有一个setTimeout中的函数,打印“定时器开始啦”
运行结果是:【立刻执行for循环啦----表演完毕!----执行then函数啦----定时器开始啦~~~】
下面这段setTimeout代码是什么意思?咱们通常说:“3s后,会执行setTimeout里的函数”
setTimeout(function(){ console.log("执行了"); },3000)
可是这种说法并不严谨,准确的解释是:
3s后,setTimeout里的函数会被推入到event queue中,而event queue(事件队列)里的任务,只有在主线程空闲时才会执行。
因此:只有在知足
这两个条件同时知足,才会在3s后执行该函数。若是主线程执行内容不少,执行时间超过3s,好比执行了10s,那么这个函数只有在10s后执行啦
到此,js引擎的执行机制解读完啦,前端的水很深,慢慢摸着吧感谢文章的提供者:ziwei3749