JS系列——学习JS的运行机制

一、js的单线程概念

众所周知,js语言是一个单线程语言,单线程也就是说同一时间只能做一件事,这个特点与他的用途有关,JS语言是运行在浏览器端的脚本语言,主要是与客户进行交互和操作DOM,所以单线程也就很好理解了。如果是多线程则会出现问题,例如,有两个线程同时对同一DOM进行添加和删除,那浏览器到底该以哪个线程为主呢?所以,单线程就避免了这个问题。但是,单线程是不是运行效率太低了?为了解决这个问题,设计师引出了同步与异步任务队列的概念。

二、同步与异步任务队列

同步任务(synchronous)就是在主线程上排队的任务,只有一个任务执行完成,才会执行下一个任务。异步任务(asynchronous)是指不进入主线程,而是进入“任务队列”的任务,只有到了该执行的时机,任务队列通知主线程可以执行该异步任务了,才会进入主线程进行执行。异步任务有:延时器setTimeout与定时器setInterval,DOM时间,es6的promise,AJAX请求(包括封装后的请求),而异步任务又分为宏任务和微任务。

console.log('1')

setTimeout(function(){
  console.log('2')
},0)

while(true) {}

如上代码:打印的是1。因为console.log('1')和while循环都是主线程上的代码,setTimeout是异步任务队列中的代码,所以从上到下先执行主线程的代码,先打印1,因为while是个死循环,所以主线程一直在执行,而不会执行异步任务。只有在主线程是空闲的时候,才会去执行异步任务。

事件循环:js主线程不断去读取异步任务的过程称为事件循环,即js主线程一到空闲时间,就会去读取异步任务队列,,执行异步任务。且这是一个循环的过程。且任务队列遵循的是“先进先出”的原则执行。

js的运行:

  • js进行预解析,代码中的所有函数,变量声明进行提前。但是不赋值
  • js运行(从上到下)执行,然后按照如上的事件循环机制进行运行
  • 异步任务的执行时机:根据实际情况来即可,比如两个延时器,一个延时5s执行,一个延时6s执行,那肯定是延时5s的先执行,又如一个ajax请求和一个延时器2s,如果ajax请求在2s内就返回结果了,那他的回调肯定是比延时器先执行,如果ajax请求在2s后才返回结果,那肯定是延时器先执行。

三、宏任务与微任务

宏任务与微任务同属于异步任务

宏任务包括:script(全局任务), setTimeout, setInterval, setImmediate, I/O, UI rendering。
微任务包括: new Promise().then(回调), process.nextTick, Object.observe(已废弃), MutationObserver(html5新特性)
同时有宏任务和微任务,那是先执行哪个呢?

我们先看看如下代码会打印什么?

            // 1
            console.log(1)
            
			// 2
			Promise.resolve().then(function () {
			
			   console.log(2)
			
			})
			// 3
			new Promise(function(resolve, reject){
			
			    console.log(3)
			
			    resolve()
			
			}).then(function () {
			    // 4
			    console.log(4)
			    // 5
			    setTimeout(function () {
			
			        console.log(5)
			
			    })
			
			})
			// 6
			console.log(6)
			// 7
			setTimeout(function () {
                // 9
			    console.log(9)
			    Promise.resolve().then(function () {
			        
			        console.log(7)
			
			        setTimeout(function () {
			
			            console.log(8)
			
			        })
			
			    })
			
			})

我们先把如上代码分成几个部分:

我们先看看主线程部分的代码有哪些?

首先1、6肯定是,这两个不包含任何异步操作,3因为是new Promise,是构造函数,所以也是,但是3中的.then()是属于回调,是异步函数里面的微任务

所以我们也可以分出异步有哪些?

异步包括:2、7以及3里面的.then()

按照先执行主线程的同步操作可知:肯先是先执行,1、3、6,然后在执行微任务,即执行2、4。打印完4后要注意,这里遇到了一个宏任务--setTimeout,程序会先把该宏任务放入队列,然后继续执行,7部分的setTimeout,所以打印9,在这里面又遇到了微任务,直接执行。所以打印7,然后再执行又遇到了setTimeout,把他放入队列,然后执行完微任务后,再去集中执行宏任务,5部分的setTimeout先入队列,所以先执行,所以先打印5,再打印8

所以最终打印结果就是:1,3,6,2,4,9,7,5,8
总结:有宏任务先执行宏任务,setTimeout也是宏任务,里面代码没有立即执行是因为这是延时器,需要特定时机执行,会先放入任务队列。执行完第一波宏任务后如果没有宏任务则开始执行微任务,执行完所有微任务队列后再去执行宏任务队列(执行微任务队列途中遇到宏任务,可以立即执行的则立即执行,如定时器则加入宏任务队列),如此循环。即:第一波宏任务——第一波微任务——第二波宏任务——第二波微任务.......

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值