js运行机制

核心概念:

1.js是单线程的

2.浏览器当中的eventloop

3.nodejs中的eventloop

js是单线程的,如果有复杂耗时的操作怎么办?有可能会导致页面卡死

eventloop就是为了解决这些问题,它的核心是异步队列,把耗时的任务放在异步队列中执行,执行完成之后再去唤起主线程

异步队列存在栈中,同步任务存在队列中,当队列中的任务执行完之后就会从栈中取出任务放在队列中执行

队列是先进先出,栈是后进先出

异步队列分为宏任务队列和微任务队列

任务执行顺序:

先执行宏任务(整个script就是一个宏任务)=》遇到promise(微任务)放入微任务队列里继续执行=》直到把所有的同步任务完成之后去执行微任务队列=》微任务队列执行完之后执行下一个宏任务

宏任务:script,settimeout,setinterval,requestAnmationFrame

微任务:promise,mutationObserver(async await实质上可以装换为promise,也是微任务)

具体实例:

  案例一

执行结果:

分析:

1.宏任务: setTimeout

2.微任务:promise构造函数中是同步的状态,then也是一个promise,是一个微任务

3.执行顺序:同步:promise init ,promise end,微任务:promise result:1,宏任务:timeout

案例二

 执行结果:

 

 1.settimeout1放在宏任务队列中

2.promise微任务执行 promise2

3.settimeout2宏任务放在宏任务队列中

4,.从宏任务队列中取出settimeout1执行timeout1

5.执行微任务promise1

6.执行宏任务timeout2

案例三

执行结果:

 分析:

 1.await默认返回一个promise,await相当于被包裹在resolve中

 2.上面的代码等价于

 

fn的then方法中打印了res,按理说会打印出return的一个对象,但是打印出了1234 ,这是为什么呢?

3.promise规范中约定如果有then方法并且是对象,就会当成promise处理

 

 案例四

 分析:

1.async1 start是同步代码

2.执行async2,返回一个promise,asyn2也是一个同步任务

3.async1 end是微任务,script是同步任务,优先级更高,所以会先打印script

上面的代码等同于

 

 案例五

执行结果:

 分析:

1.执行同步的script start

2.执行async1,会打印async1 start

3.new Promise 构造函数中是同步执行的,会打印promise1

4.promise没有resolve方法,导致promise中的函数一直都不会完成,所以后面的代码都不会执行了

案例六

 执行结果:

 

 

 

 分析:

1.执行同步script start

2.settimeout加入宏任务队列

3.执行async1,打印同步的async1 start

4.等待async2执行完,打印async2,返回一个promise,打印async1 end 进入微任务队列

5.执行同步任务promise

6.then中的加入微任务队列

7.执行同步的script end,至此,第一轮宏任务已经完后

8.读取微任务列表,执行完成,即执行打印async1 end ,promise2,promise3,promise4,微任务队列执行完毕

9.执行下一个宏任务settimeout,打印settimeout

 案例七

  执行结果:

 

 分析:

1.setTimeout放在宏任务队列中

2.执行async1,将then放在微任务队列中

3...

执行结果:

 

分析:

1.resolve是promise,每个promise都是thenable对象,都有then方法,resolve处理thenable也会包裹一层promise

2.async2是一个promise所以async2这相当于有两层promise,就会推迟两次执行

 执行结果:

 

分析:

1.async2打印这里不是一个promise,只会推迟执行一次

2.如果async中只return一个基本类型,那么执行结果和最初的执行结果一样

 nodejs中的eventloop

js应用程序经过v8的编译之后经过node的api执行libuv

libuv就是eventloop完成的,libuv中有工作队列,当有任务完成时会触发一个callback回到nodeapi然后回到应用程序

 

 

 

 

定时器阶段=》循环回调=》内部使用的一些钩子函数=》poll阶段(监听)执行所有异步任务的io=》check节点(setimmediate)

nexttick在当前任务完成之后下一个阶段任务开始之前执行

nodejs中的任务队列

宏任务:settimeout,setinterval,setimmediate,io

微任务:promise,pross.nextTick(优先级比promise高)

案例一

 

 多执行几次之后发现settimeout和setImmediate执行先后是不固定的,为什么会产生这种情况呢?

settimeout是在timer阶段执行的,而setimmediat是在check阶段。如果在poll阶段timer没有加入到执行队列中时,就先执行check阶段,等下一个轮询再执行timer。如果已经加入到执行队列中,就会先执行settimeout,程序执行也是有耗时的。

案例二

执行结果:

 

 setimmediate始终在settimeout执行之前

分析:

由于事件都是在poll阶段注册的,所以在poll阶段timer是没有时间到期的,所以在执行完poll阶段会马上执行check阶段,等下一个时钟周期才会触发timer

案例三

 

nodejs都是基于回调式的写法,nodejs的api回调的第一个参数都是error,第二个值才是data。那么是怎么抛出错误的呢?

一般是使用上面的方式,当参数arg的类型不正确的时候就在下个时钟周期的时候执行callback抛出异常,这样不会因为一个错误影响程序的运行

案例四

执行结果:

 

每个阶段尾部执行nextTick,setTmmediate是在check阶段触发的时候执行,所以nextTick会先执行

不同版本中的Eventloop是不同的

案例一

 

 

 

 在node11版本之后会先打印time1再打印promiss1,time2,promiss2

在node11之前会打印time1,time2,promiss1,promiss2
timer阶段不同版本执行时机的变化:

node11之前先执行所有的宏任务再执行微任务,之后是先把当前任务的所有内容执行完再执行下个任务

案例二

 

check阶段不同版本的变化:

node11之前:immediate1   immediate2    immediate3    immediate4     promise resolve

node11之后:  immediate1   immediate2  promise resolve   immediate3    immediate4       

11之后先执行宏任务然后执行宏任务的微任务,然后再执行下一个宏任务

案例三

 

 node11之后

 

 node11之前next tick是在最后执行



posted @ 2021-11-03 17:30  橘橙夏日  阅读(243)  评论(0编辑  收藏  举报