從0到1,理解異步編程方案Promise(0)

這是我參與8月更文挑戰的第5天,活動詳情查看:8月更文挑戰javascript

  1. 理解什麼是觀察者模式
  2. 理解什麼是發佈訂閱模式
  3. 理解什麼是queueMicrotask()

本篇是Promise的基本前置知識,讓手寫一個Promise變的不在困難!!!,這是構建Promise的0前端

1. 觀察者模式

1.1 基本理解

如圖【觀察者模式簡圖】:java

觀察者模式簡圖.png 觀察者模式講述的是一對多的關係,簡單的來講就是一個對象的狀態改變,觸發不一樣觀察者動做迴應,在《圖解設計模式》一書當中,觀察者模式就是作狀態管理的一種設計模式

按圖,咱們開始實現一個觀察者模式瀏覽器

1.2 實現一個簡單的觀察者模式示例

  1. 建立一個Observer的類
  2. 建立一個被觀察的類
  3. 被觀察的類須要添加一個方法addObserver,來收集實例化的Observer
  4. 狀態改變,通知實例化的Observer
// 建立一個Observer的類
class Observer {
	constructor(name,action = ()=>{}) {
	    this.name = name;
		this.action = action
	}
	runAction(state){
		this.action(state,this.name)
	}
}
// 建立一個被觀察的類
class Subject {
	constructor(name,state) {
	    this.name = name;
		this.nowState = state;
		
		this.oldState = null;
		this.obseverList = new Set();
	}
	// 被觀察的類須要添加一個方法addObserver,來收集實例化的Observer
	addObserve(obsever){
		this.obseverList.add(obsever)
		return this
	}
	// 狀態改變,通知實例化的Observer
	notifyObserve(state){
		this.nowState = state;
		if(this.oldState!==this.nowState){
			for(let item of this.obseverList){
				item.runAction(this.nowState)
			}
			this.oldState = this.nowState
		}
		return this;
	}
}
const teacherA = new Observer('老師A',(state,name)=>{
	if(state === 'playing'){
		console.log( name+'發現你在玩,打電話找你家長' )
	}else if( state === 'studying'){
		console.log( name+'狠狠的表揚了你' )
	}
})

const teacherB = new Observer('老師B', (state,name)=>{
	if(state === 'playing'){
		console.log( name+'發現你在玩,罰站30分鐘' )
	}
})

const deskmateA = new Observer('小明',(state,name)=>{
	if(state === 'eating'){
		console.log( name+'發現你在吃東西,所以他也開始吃' )
	}
})

const deskmateB = new Observer('小f',(state,name)=>{
	if(state === 'eating'){
		console.log( name+'發現你在吃東西,所以他也開始吃' )
	}
})
const You = new Subject('你','studying')
You.addObserve(deskmateA).addObserve(teacherA).addObserve(teacherB)
You.notifyObserve('playing')
You.notifyObserve('eating')
You.notifyObserve('studying')
複製代碼

上面就是一個很是簡單的觀察者模式的實現。markdown

從中能夠清楚的看到,Subject和各個Observer是鬆耦合關係。當state改變的時候,統一調取各個實例化ObserverrunAction去根據狀態執行相應的邏輯就行了。異步

2 發佈訂閱模式

2.1 基本理解

發佈訂閱模式和觀察者模式,大致上很像(好比尤大大就認爲發佈訂閱模式和觀察者模式就是同樣的)。這裏就不討論大佬的思想,畢竟咱們都還不到掌控代碼的程度。不過能夠用觀察者模式去類比發佈訂閱模式(發佈訂閱模式裏的Publisher,就是觀察者模式裏的Subject,而Subscriber,就是Observer),只不過在發佈訂閱模式裏面多了一個第三方Observer來轉發,而不是Subscriber直接notify狀態給Publisher函數

在前端中,其實瀏覽器監聽事件就是一個典型的發佈訂閱模式。例如,document.addEventListener('click',()=>{}), document就是被監聽也就是Publisher,'click'表明發佈內容Subject,後面的函數的意思就是,訂閱到這個事件是click那就執行這個函數。順着這個來,就能出圖了oop

如圖【發佈訂閱模式】:post

發佈訂閱模式.png

2.2 實現一個簡單的發佈訂閱模式示例

  1. 建立一個第三方觀察者Observer
  2. 給第三方的觀察者一個addEventListener來添加訂閱某消息和訂閱該消息的Subscriber行爲,只是這裏要注意的是,同一個消息不止一個Subscriber的行爲能夠定,繼續添加Subscriber的行爲
  3. 給第三方的觀察者一個removeEventListener能夠訂閱解除,解除分兩種一種是解除單個Subscriber對某個消息的訂閱,和直接解除對某個消息的訂閱
  4. 給第三方的觀察者一個notify方法接受到Publisher的狀態,觸發Subscriber行爲
class Observe {
	constructor() {
	    this.publisherMap = new Map();
	}
	/* * @param { String } type 訂閱消息的類型 * @param { Function } actionfn 相應的Subscriber的動做,也是推送消息的目標的動做(Subscriber) **/
	addEventListener(type,actionfn){
		if( !actionfn ){
			console.error('綁定失敗')
		}
		let actionfnList = new Set();
		if(this.publisherMap.has(type)){
			actionfnList = this.publisherMap.get(type)
		}
		actionfnList.add(actionfn)
		this.publisherMap.set(type,actionfnList)
	}
	// 取消訂閱 Publisher
	removeEventListener(type,actionfn){
		if( this.publisherMap.has(type) && actionfn){
			const actionfnList = this.publisherMap.get(type)
			if(actionfnList.size){
				actionfnList.delete(actionfn)
			}else{
				this.publisherMap.delete(type)
			}
		}else if( this.publisherMap.has(type) && !actionfn){
			this.publisherMap.delete(type)
		}else{
			console.error('暫無這個消息隊列')
		}
	}
	// 觸發 Subscriber 的動做,也叫發佈通知消息
	notify(type){
		if(this.publisherMap.has(type)){
			const actionfnList = this.publisherMap.get(type)
			for(let subscriberAction of actionfnList){
				subscriberAction(this);
			}
		}
	}
}
// 老師任命班長來監聽你的狀態
const monitor = new Observe()
const yourState = ['studying','eating']
const teacherAction = function(){
	console.log('要很很的表揚你')
}
const deskmeatAction = function(e){
	console.log('一塊兒吃東西',e)
}
monitor.addEventListener(yourState[0],teacherAction)
monitor.addEventListener(yourState[0],()=>{
	console.log('給你一朵大大的紅花')
})
monitor.addEventListener(yourState[1],deskmeatAction)
monitor.notify(yourState[0])
monitor.notify(yourState[1])
複製代碼

從中能夠發現,發佈訂閱模式裏,發佈者訂閱者,不是鬆耦合,而是徹底解耦的。他們之間的聯繫由第三方的Observer來協調。從代碼實現上來看,必要的構造函數只實現第三方的Observer便可

從中也能發現,發佈訂閱模式和觀察者模式最大的區別在於,在發佈訂閱模式裏,發佈者,並不會直接通知訂閱者,換句話說,發佈者和訂閱者,彼此互不相識。這也是徹底解耦的特色

3. 你所不知道的queueMicrotask()

JavaScript 中經過 queueMicrotask()使用微任務

這裏不對微任務宏任務作深刻研究,只簡單說明一下:任務能夠當作一條一條的執行語句。,通常狀況下是同步運行的,從上而下,當遇到異步的事件,就須要將異步事件推入事件循環隊列,而事件循環隊列有兩種,一種是微任務循環隊列,一種是宏任務循環隊列。微任務先於宏任務執行。

簡單使用以下:

console.log('a')
window.queueMicrotask(()=>{
	console.log('b')
})
console.log('c')
複製代碼

掌握上面的內容,手寫Promise將變的異常輕鬆。徹底不須要死記硬背了!!!

參考資料

  1. 觀察者模式 vs 發佈訂閱模式h
  2. 圖解設計模式
  3. queueMicrotask
相關文章
相關標籤/搜索