同步和异步学习笔记

216 阅读7分钟

一.单线程理解

javascript是单线程,且和DOM渲染共用一个进程,因为JS可以修改DOM结构,DOM渲染时JS就停止,也就是说一定时间内只能执行一段代码。

就像你一个人干家务,拖地,洗衣,缝内裤。一件一件的干,30分钟拖完地才能继续干下一件事缝补内裤,洗衣服就得等缝内裤结束后才能进行。

所以哪吒就很适合做家务,三头六臂。

二.同步理解

javascript是从上往下执行,从左往右执行代码。

既然是一行一行从上往下执行,执行中某块代码卡住了,下面的代码你就别想继续执行。

例子:

console.log(100)

alert(200)

console.log(300)

分析:先打印100 程序往下执行,浏览器弹出框显示200,不点击确定按钮,程序无法往下执行,就无法打印出300,照成了阻塞代码执行。

结论:事一件一件的干,前一件干完才能干下一件,拖着一件事三四天不干,下面的事情没法干。哎呦,这行为有点眼熟。

三.异步理解

异步是为了解决单线程等待问题。异步不按照代码顺序执行,所以执行某段代码时,没有接收到结果前,可以继续执行后续操作,不需要进行等待,是非阻塞的。

列子:

console.log(100)

setTimeout(function(){
        console.log(200)
},1000)

console.log(300)

分析:程序开始执行从上往下走,先打印100,遇见setTimeout把他先放到一边,暂存起来。程序继续往下执行,打印300。这时程序瞧着下面没有要执行的代码,跑到暂存区域看看,有个setTimeout需要执行,执行前发现还有条件,需要1秒之后执行,那就等一秒,时间一到就执行里面代码。

输出结果就是 100 , 300 , 200

四.异步的应用场景:

1.定时任务(setInterval或setTimeout) 2.网络请求(ajax) 3.绑定事件 (DOM事件监听)

五.异步和同步执行顺序:

例子

setTimeout(function(){
        console.log(200)
},1000)
console.log(100) 
 

分析:代码从上往下执行,遇见setTimeout拎出来放在暂存区,也就是任务队列里,继续执行下面代码打印100,然后进入任务队列,检查有没有任务需要执行,这个任务就叫宏任务。程序发现有就执行这个任务,打印200

也就是说,同步优先级最高。同步执行的任务放到主线程按加入顺序执行,异步任务扔到任务队列,主线程执行完之后会从任务队列里按照先入先出的方式取任务。

具体顺序就是同步>微任务>宏任务。

六.Promise理解

异步是基于callback hell 回调函数执行,但callback 回调嵌套多了,就形成回调地狱。

例子:

setTimeout(function(){
        console.log(1)
        setTimeout(function(){
                console.log(2)
                setTimeout(function(){
                    console.log(3)
                    setTimeout(function(){
                            console.log(4)
                       },1000)
		},1000)
	},1000)
},1000)

结构就像这样,层层嵌套,嵌套越多看着越难受,听说跟地狱一样恐怖。所以Promise出现了,目的是更加优雅地书写复杂的异步任务。

Promise只是将callback的嵌套变成了一节一节,类似于水管一样,结构清晰。但Promise本质没有变化,还是使用callback形式。

Promise 构造函数只有一个参数,还是一个函数,这个函数在构造之后会直接被异步运行,所以我们称之为起始函数。起始函数包含两个参数 resolve 和 reject,这两个参数也是函数。

new Promise(function (resolve, reject) { console.log("Run"); });

Promise 类有 .then() .catch() 和 .finally() 三个方法,这三个方法的参数都是一个函数,.then() 可以将参数中的函数添加到当前 Promise 的正常执行序列,.catch() 则是设定 Promise 的异常处理序列,.finally() 是在 Promise 执行的最后一定会执行的序列。 .then() 传入的函数会按顺序依次执行,有任何异常都会直接跳到 catch 序列:

例子:

new  Promise(resolve=>{
        console.log(1)
}).then(value=>console.log(2))
					
console.log(3)

输出结果:1 3

这里需要说明的就是new Promise 也是同步,所以会先输出1,同步继续往下走,打印3

那么2为啥不打印?

new Promise 走到 then不会执行,会等通知,成功或者失败的状态通知。所以需要加入resolve()或reject()

new  Promise(resolve=>{
        console.log(1)
        resolve()
}).then(value=>console.log(2))
					
console.log(3)

输出结果:1 3 2

分析:代码执行new Promise 打印1,then等到通知resolve(),才会把任务加入到微任务队列,继续往下走打印3,然后看看微任务队列有没有任务,发现有打印2

上面说过同步优先级最高,然后就是微任务,最后宏任务。同步>微任务>宏任务

微任务包括:promise.then(),process.nextTick()等

宏任务包括:setTimeOut(),setInterval()等

列子:

        console.log(1)	
	setTimeout(function(){
	   console.log(2)
	})
			
	new  Promise(resolve=>{
                console.log(3)
                resolve()
	}).then(value=>console.log(4))
						
	console.log(5)

输出结果:1 3 5 4 2

分析:同步优先打印1,往下执行setTimeout,加入宏任务队列,等待处理。继续往下走new Promise时同步,所以打印3,then得到resolve()成功通知,把任务加入到微任务队列,等待处理。继续往下走打印5。同步走完,进入到微任务列队,发现任务打印出4。微任务列队没有其他任务,去宏任务列队瞧瞧,发现有任务打印出2

例子:

	console.log(1)	
	setTimeout(function(){
	   console.log(2)
	})
			
	new  Promise(resolve=>{
                console.log(3)
		setTimeout(function(){
                        resolve() 
                        console.log(4)
                })
			
	}).then(value=>console.log(5))
						
	console.log(6)

输出结果:1 3 6 2 4 5

分析:同步优先打印1,往下执行setTimeout,加入宏任务队列,继续往下走new Promise打印3,继续执行setTimeout加入宏任务队列,then没有得到通知不执行,继续往下打印6

同步走完打印1 3 6

程序开始走微任务列队没有,走宏任务列队,任务队列里按照先入先出的方式,所以先打印2,在打印4。继续走给then发通知说成功了,然后微任务执行打印5

这就既然是微任务>宏任务,5 应该可以比4 先打印,这是因为setTimeout这条宏任务已经进入主程序,他执行完才能进入微任务,所以45 前面打印

例子:

	console.log(1)	
	setTimeout(function(){
	   console.log(2)
	},1000)
			
	new  Promise(resolve=>{
		console.log(3)
		setTimeout(function(){
			console.log(4)
			resolve()   
		})
			
	}).then(value=>console.log(5))
						
	console.log(6)
            
            

输出结果:1 3 6 4 5 2

分析:同步优先1 3 6 先依次打印出来,同样这里先走宏任务,先打印4 再 打印5。前面说了任务队列里按照先入先出的方式,第一个setTimeout先进入的,应该先打印2,怎么会是45

进入宏任务列队中,发现有两个宏任务,setTimeout1和setTimeout2。这里先说下异步执行条件,1.同步执行结束;2.异步执行状态可以执行;3.前面有可以执行的但是他条件不满足,所以你可以执行了。

按照先入先出,找的第一个setTimeout(setTimeout1),他说等他1秒。程序发现时间不满足,就去找第二个setTimeout(setTimeout2),发现他没有这多B事,就立即执行setTimeout2,打印4,继续走看还有个微任务就打印出来5。第一个setTimeout时间满足,到了1秒,开始打印2,要是设置24小时,那就等一天再打印。所以得出结论就是爱情也是一样的,不要等待

注: * 加入时间条件的setTimeout,有时候不一定在时间条件内输出,可能会超过当前时间条件,原因就是前面的任务时间太长,加上setTimeout延迟时间,输出结果时间是大于延迟时间的。*

本文章是学习知识点的梳理笔记,如有错误地方请指正,谢谢。