观察者模式

50 阅读5分钟

为什么要用观察者模式:

  1. 观察者模式的核心优势是观察者和事件消费者充分解耦。这样生产者只需要负责触发事件即可,消费者只需要专注处理逻辑即可,它们不需要彼此关心对方的存在和内在逻辑。同时一个事件发生以后也可以由任意多个消费者来进行处理,使得应用的逻辑可以变得更加清晰,避免产生耦合在一起的面条代码。

有什么弊端:

  1. 观察者模式也是有坏处的,即它强行将代码间的关系进行分离,使得开发者在阅读和维护代码的时候不容易一眼看到不同代码之间的逻辑关系。因此对于逻辑关联很强的代码,一般不建议使用观察者模式进行组织。
  1. const pending = 'pending'
    const resolved = 'resolved'
    const rejected = 'rejected'
    const resolvepromise = (promise2, x, resolve, reject) => {
      if (promise2 === x) {
        return reject(new TypeError('不能返回自身'))
      }
      if (typeof x === 'object' && typeof x !== null || typeof x === 'function') {
        //由于测试的时候即调用成功,也调用失败resolve(),reject()
        try {
          let then = x.then
          if (typeof then === 'function') {//是一个promise
            then.call(x, y => {
              resolvepromise(promise2, y, resolve, reject)//什么意思就是说这个,resolve可能继续返回一个promise,所以想递归不断得到一个普通值后再去返回
    
            }, r => {
              reject(r)
            })
    
          } else {
            resolve(x)//这里就是说这个x亦可能是普通值then里面返回一个普通值自然,调用promise2的一个resolve(x)
          }
    
        } catch (error) {
          reject(error)
        }
    
      }
    
    }
    class Promise {
        constructor(executor) {
            this.status = pending
            this.value = undefined
            this.reason = undefined
            this.onfullfiledCallbacks = []
            this.onrejectedCallbacks = []
            let resolve = (value) => {
                if (this.status === pending) {//加if判断是为了能够限制,状态不能随意改变
                    this.value = value
                    this.status = resolved
    		//订阅,开始执行之前暂存的成功的回调,或者失败的回调
                    this.onfullfiledCallbacks.forEach(fn => fn())
                }
            }
            let reject = (reason) => {
                if (this.status === pending) {
                    this.status = rejected
                    this.reason = reason
                    this.onrejectedCallbacks.forEach(fn => fn())
                }//用箭头函数是因为要来去继承外部代码快的this
    
            }
            try {
                executor(resolve, reject)
            } catch (error) {
                reject(error)
            }
        }
    
        then(onfullfiled, onrejected) {
            let promsie2 = new Promise((resolve, reject) => {
                //同步的情况
    	    // 当判断状态发生变更的时候,去通知执行对应成功的回调,或是失败的回调
                if (this.status === resolved) {
                    setTimeout(() => {
                        try {
                            let x = onfullfiled(this.value)//这个是then()方法返return 的一个结果
                            ResolvePromise(x, promsie2, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    })
    
                    if (this.status === rejected) {
                        setTimeout(() => {
                            try {
                                let x = onrejected(this.reason)//这个是then()方法返return 的一个结果
                                ResolvePromise(x, promsie2, resolve, reject)
                            } catch (error) {
                                reject(error)
                            }
                        })
                    }
                    //异步的情况,当立即执行函数内部存在异步,先进行发布
                    if (this.status === pending) {
                        this.onfullfiledCallbacks.push(() => {
                            setTimeout(() => {
                                try {
                                    let x = onfullfiled(this.value)//这个是then()方法返return 的一个结果
                                    ResolvePromise(x, promsie2, resolve, reject)
                                } catch (error) {
                                    reject(error)
                                }
                            })
    
                        })
                        this.onrejectedCallbacks.push(() => {
                            setTimeout(() => {
                                try {
                                    let x = onrejected(this.reason)//这个是then()方法返return 的一个结果
                                    ResolvePromise(x, promsie2, resolve, reject)
                                } catch (error) {
                                    reject(error)
                                }
                            })
    
                        })
    
                    }
    
                }
    
    
    
            })
            return promsie2
    
        }
    }
    
    module.exports = Promise
    
  1. promise这里的回调
  2. //这里会存在一个问题就是当立即执行函数内部是异步的,当执行到微任务时先将立即执行函数push到成功或失败的数组(发布)
    const result = new Promise((resolve, reject) => {
      setTimeout(() => {
        // reject(222)
        resolve(222)
    
      }, 400);
    
    }).then((value) =>
      console.log('value', value), (reason) => reason)
    console.log('result', result)
    

//*[@id="cnblogs_code_open_57a219ff-9040-47ad-bf9b-92537de7b897"]/div[2]/span

/html/body/div[4]/div/div[1]/div[2]/div[3]/div/div[2],这个Xpath定位情况是否可用。

Mitt 库

  1. export type EventType = string | symbol;
    
    // An event handler can take an optional event argument
    // and should not return a value
    export type Handler<T = unknown> = (event: T) => void;
    export type WildcardHandler<T = Record<string, unknown>> = (
    	type: keyof T,
    	event: T[keyof T]
    ) => void;
    
    // An array of all currently registered event handlers for a type
    export type EventHandlerList<T = unknown> = Array<Handler<T>>;
    export type WildCardEventHandlerList<T = Record<string, unknown>> = Array<WildcardHandler<T>>;
    
    // A map of event types and their corresponding event handlers.
    export type EventHandlerMap<Events extends Record<EventType, unknown>> = Map<
    	keyof Events | '*',
    	EventHandlerList<Events[keyof Events]> | WildCardEventHandlerList<Events>
    >;
    
    export interface Emitter<Events extends Record<EventType, unknown>> {
    	all: EventHandlerMap<Events>;
    
    	on<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>): void;
    	on(type: '*', handler: WildcardHandler<Events>): void;
    
    	off<Key extends keyof Events>(type: Key, handler?: Handler<Events[Key]>): void;
    	off(type: '*', handler: WildcardHandler<Events>): void;
    
    	emit<Key extends keyof Events>(type: Key, event: Events[Key]): void;
    	emit<Key extends keyof Events>(type: undefined extends Events[Key] ? Key : never): void;
    }
    
    /**
     * Mitt: Tiny (~200b) functional event emitter / pubsub.
     * @name mitt
     * @returns {Mitt}
     */
    export default function mitt<Events extends Record<EventType, unknown>>(
    	all?: EventHandlerMap<Events>
    ): Emitter<Events> {
    	type GenericEventHandler =
    		| Handler<Events[keyof Events]>
    		| WildcardHandler<Events>;
    	all = all || new Map();
    
    	return {
    
    		/**
    		 * A Map of event names to registered handler functions.
    		 */
    		all,
    
    		/**
    		 * Register an event handler for the given type.
    		 * @param {string|symbol} type Type of event to listen for, or `'*'` for all events
    		 * @param {Function} handler Function to call in response to given event
    		 * @memberOf mitt
    		 */
    		on<Key extends keyof Events>(type: Key, handler: GenericEventHandler) {
    			const handlers: Array<GenericEventHandler> | undefined = all!.get(type);
    			if (handlers) {
    				handlers.push(handler);
    			}
    			else {
    				all!.set(type, [handler] as EventHandlerList<Events[keyof Events]>);
    			}
    		},
    
    		/**
    		 * Remove an event handler for the given type.
    		 * If `handler` is omitted, all handlers of the given type are removed.
    		 * @param {string|symbol} type Type of event to unregister `handler` from (`'*'` to remove a wildcard handler)
    		 * @param {Function} [handler] Handler function to remove
    		 * @memberOf mitt
    		 */
    		off<Key extends keyof Events>(type: Key, handler?: GenericEventHandler) {
    			const handlers: Array<GenericEventHandler> | undefined = all!.get(type);
    			if (handlers) {
    				if (handler) {
    					handlers.splice(handlers.indexOf(handler) >>> 0, 1);
    				}
    				else {
    					all!.set(type, []);
    				}
    			}
    		},
    
    		/**
    		 * Invoke all handlers for the given type.
    		 * If present, `'*'` handlers are invoked after type-matched handlers.
    		 *
    		 * Note: Manually firing '*' handlers is not supported.
    		 *
    		 * @param {string|symbol} type The event type to invoke
    		 * @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler
    		 * @memberOf mitt
    		 */
    		emit<Key extends keyof Events>(type: Key, evt?: Events[Key]) {
    			let handlers = all!.get(type);
    			if (handlers) {
    				(handlers as EventHandlerList<Events[keyof Events]>)
    					.slice()
    					.map((handler) => {
    						handler(evt!);
    					});
    			}
    
    			handlers = all!.get('*');
    			if (handlers) {
    				(handlers as WildCardEventHandlerList<Events>)
    					.slice()
    					.map((handler) => {
    						handler(type, evt!);
    					});
    			}
    		}
    	};
    }
    

这里去结合官方在线实例进行补充。

image.png

function observe(target) {
    if(target && typeof target === 'object') {
        Object.keys(target).forEach((key)=> {
            defineReactive(target, key, target[key])
        })
    }
}
data(){
a:{
b:{
1
}
}

}

function defineReactive(target, key, val) {
    // 属性值也可能是object类型,这种情况下需要调用observe进行递归遍历
    observe(val)
    Object.defineProperty(target, key, {
        enumerable: true,
        configurable: false, 
        get: function () {
            return val;
        },
        set: function (value) {
            console.log(`${target}属性的${key}属性从${val}值变成了了${value}`)
            val = value
        }
    });
}

下面实现订阅者 Dep:

// 定义订阅者类Dep
class Dep {
    constructor() {
        // 初始化订阅队列
        this.subs = []
    }
  
    addSub(sub) {
        this.subs.push(sub)
    }
  
    notify() {
        this.subs.forEach((sub)=>{
            sub.update()
        })
    }
}

现在我们可以改写 defineReactive 中的 setter 方法,在监听器里去通知订阅者了:

function defineReactive(target, key, val) {
    const dep = new Dep()
    // 监听当前属性
    observe(val)
    Object.defineProperty(target, key, {
        set: (value) => {
            // 通知所有订阅者
            dep.notify()
        }
    })
}