這是我參與8月更文挑戰的第5天,活動詳情查看:8月更文挑戰javascript
- 理解什麼是觀察者模式
- 理解什麼是發佈訂閱模式
- 理解什麼是
queueMicrotask()
本篇是Promise
的基本前置知識,讓手寫一個Promise
變的不在困難!!!,這是構建Promise
的0前端
如圖【觀察者模式簡圖】:java
觀察者模式講述的是一對多的關係,簡單的來講就是一個對象的狀態改變,觸發不一樣觀察者動做迴應,在《圖解設計模式》一書當中,觀察者模式就是作狀態管理的一種設計模式
按圖,咱們開始實現一個觀察者模式瀏覽器
Observer
的類addObserver
,來收集實例化的Observer
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
改變的時候,統一調取各個實例化Observer
的runAction
去根據狀態執行相應的邏輯就行了。異步
發佈訂閱模式和觀察者模式,大致上很像(好比尤大大就認爲發佈訂閱模式和觀察者模式就是同樣的)。這裏就不討論大佬的思想,畢竟咱們都還不到掌控代碼的程度。不過能夠用觀察者模式去類比發佈訂閱模式(發佈訂閱模式裏的Publisher
,就是觀察者模式裏的Subject
,而Subscriber
,就是Observer
),只不過在發佈訂閱模式裏面多了一個第三方Observer
來轉發,而不是Subscriber
直接notify
狀態給Publisher
函數
在前端中,其實瀏覽器監聽事件就是一個典型的發佈訂閱模式。例如,document.addEventListener('click',()=>{})
, document
就是被監聽也就是Publisher
,'click'表明發佈內容Subject
,後面的函數的意思就是,訂閱到這個事件是click
那就執行這個函數。順着這個來,就能出圖了oop
如圖【發佈訂閱模式】:post
Observer
類addEventListener
來添加訂閱某消息和訂閱該消息的Subscriber
行爲,只是這裏要注意的是,同一個消息不止一個Subscriber
的行爲能夠定,繼續添加Subscriber
的行爲removeEventListener
能夠訂閱解除,解除分兩種一種是解除單個Subscriber
對某個消息的訂閱,和直接解除對某個消息的訂閱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
便可
從中也能發現,發佈訂閱模式和觀察者模式最大的區別在於,在發佈訂閱模式裏,發佈者,並不會直接通知訂閱者,換句話說,發佈者和訂閱者,彼此互不相識。這也是徹底解耦的特色
queueMicrotask()
在JavaScript
中經過 queueMicrotask()
使用微任務
這裏不對微任務宏任務作深刻研究,只簡單說明一下:任務能夠當作一條一條的執行語句。,通常狀況下是同步運行的,從上而下,當遇到異步的事件,就須要將異步事件推入事件循環隊列,而事件循環隊列有兩種,一種是微任務循環隊列,一種是宏任務循環隊列。微任務先於宏任務執行。
簡單使用以下:
console.log('a')
window.queueMicrotask(()=>{
console.log('b')
})
console.log('c')
複製代碼
掌握上面的內容,手寫Promise
將變的異常輕鬆。徹底不須要死記硬背了!!!