这是我参与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
将变的异常轻松。彻底不须要死记硬背了!!!