React

发布订阅者模式(观察者模式)

2020-12-18  本文已影响0人  Raral

概念: 其定义对象间一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。

发布-订阅.png

举例说明:

发布-订阅模式场景

webpack中 tapable

tapable 是一个类似于 Node.js 中的 EventEmitter的库,是一个发布订阅者模式,但更专注于自定义事件的触发和处理。webpack 通过 tapable 将实现与流程解耦,所有具体实现通过插件的形式存在。

/**
 * tabaple 是 基于事件流的框架,发布订阅者模式
 * 
 * 1\. 同步的 同步钩子构造函数
 *      SyncHook                依赖的回调函数 执行时没有任何关系 独立执行
 *      SyncBailHook            依赖的回调函数 执行顺序必须有保证,执行下一个必须保证上一个正确
 *      SyncWaterfallHook       依赖的回调函数 执行下一个回调函数的参数是 上一个回调函数的返回值
 *      SyncLoopHook            依赖的回调函数 可能某一个函数需要执行多次后才执行下一个函数
 * 
 * 2\. 异步的
 * 
 */

class SyncHook {
    constructor(args) {
        this.tasks = [];// 存放呆要执行的任务
    }

    tap(name,callback) {// 注册新的任务 存放到tasks中
        this.tasks.push(callback)
    }
    call(...args) {// 执行有关联的任务 tasks 
        this.tasks.forEach(callback => {
            callback&&callback(...args);
        })
    }

}

let hook = new SyncHook(["name"]);
hook.tap("react", function(name) {
    console.log("react", name)
})
hook.tap("node", function(name) {
    console.log("node", name)
})

hook.call("xxx")

//react xxx
//node xxx

/**
 * tabaple 是 基于事件流的框架,发布订阅者模式
 * 
 * 1\. 同步的 同步钩子构造函数
 *      SyncHook              依赖的回调函数 执行时没有任何关系 独立执行
 *      SyncBailHook         依赖的回调函数 执行顺序必须有保证,执行下一个必须保证上一个正确
 *      SyncWaterfallHook    依赖的回调函数 执行下一个回调函数的参数是 上一个回调函数的返回值
 *      SyncLoopHook
 * 
 * 2\. 异步的
 * 
 */

class SyncBailHook {
    constructor(args) {
        this.tasks = [];// 存放呆要执行的任务
    }

    tap(name,callback) {// 注册新的任务 存放到tasks中
        this.tasks.push(callback)
    }
    call(...args) {// 执行有关联的任务 tasks 
        let ret,index = 0;
        do {    
            ret = this.tasks[  index ++ ](...args);

        } while (ret === undefined && index < this.tasks.length);
    }

}

let hook = new SyncBailHook(["name"]);
hook.tap("react", function(name) {
    console.log("react", name)
    return "像停止" //下一个任务不执行
})
hook.tap("node", function(name) {
    console.log("node", name)
})

hook.call("xxx")

//react xxx
//node xxx

/**
 * tabaple 是 基于事件流的框架,发布订阅者模式
 * 
 * 1\. 同步的 同步钩子构造函数
 *      SyncHook              依赖的回调函数 执行时没有任何关系 独立执行
 *      SyncBailHook         依赖的回调函数 执行顺序必须有保证,执行下一个必须保证上一个正确
 *      SyncWaterfallHook    依赖的回调函数 执行下一个回调函数的参数是 上一个回调函数的返回值
 *      SyncLoopHook
 * 
 * 2\. 异步的
 * 
 */

class SyncWaterfallHook {
    constructor(args) {
        this.tasks = [];// 存放呆要执行的任务
    }

    tap(name,callback) {// 注册新的任务 存放到tasks中
        this.tasks.push(callback)
    }
    call(...args) {// 执行有关联的任务 tasks 
        let [first, ...others] = this.tasks;
        let ret = first(...args);
        others.reduce((acc,cur) => {
            return cur(acc)
        }, ret)
    }

}

let hook = new SyncWaterfallHook(["name"]);
hook.tap("react", function(name) {
    console.log("react", name)
    return "react" 
})
hook.tap("node", function(data) {
    console.log("node", data)
    return data
})
hook.tap("vue", function(data) {
    console.log("vue", data)

})

hook.call("xxx")

//react xxx
//node xxx

/**
 * tabaple 是 基于事件流的框架,发布订阅者模式
 * 
 * 1\. 同步的 同步钩子构造函数
 *      SyncHook              依赖的回调函数 执行时没有任何关系 独立执行
 *      SyncBailHook         依赖的回调函数 执行顺序必须有保证,执行下一个必须保证上一个正确
 *      SyncWaterfallHook    依赖的回调函数 执行下一个回调函数的参数是 上一个回调函数的返回值
 *      SyncLoopHook
 * 
 * 2\. 异步的
 * 
 */

class SyncWaterfallHook {
    constructor(args) {
        this.tasks = [];// 存放呆要执行的任务
    }

    tap(name,callback) {// 注册新的任务 存放到tasks中
        this.tasks.push(callback)
    }
    call(...args) {// 执行有关联的任务 tasks 
        let [first, ...others] = this.tasks;
        let ret = first(...args);
        others.reduce((acc,cur) => {
            return cur(acc)
        }, ret)
    }

}

let hook = new SyncWaterfallHook(["name"]);
hook.tap("react", function(name) {
    console.log("react", name)
    return "react" 
})
hook.tap("node", function(data) {
    console.log("node", data)
    return data
})
hook.tap("vue", function(data) {
    console.log("vue", data)

})

hook.call("xxx")

//react xxx
//node xxx

/**
 * tabaple 是 基于事件流的框架,发布订阅者模式
 * 
 * 1\. 同步的 同步钩子构造函数
 *      SyncHook              依赖的回调函数 执行时没有任何关系 独立执行
 *      SyncBailHook         依赖的回调函数 执行顺序必须有保证,执行下一个必须保证上一个正确
 *      SyncWaterfallHook    依赖的回调函数 执行下一个回调函数的参数是 上一个回调函数的返回值
 *      SyncLoopHook         依赖的回调函数 中可能像让某一个函数执行 多次,再执行下一个回调函数
 * 
 * 2\. 异步的
 * 
 */

class SyncLoopHook {
    constructor(args) {
        this.tasks = [];// 存放呆要执行的任务
    }

    tap(name,callback) {// 注册新的任务 存放到tasks中
        this.tasks.push(callback)
    }
    call(...args) {// 执行有关联的任务 tasks 
        this.tasks.forEach(task => {
            let ret;
            do {
                ret = task(...args);
            } while (ret != undefined);
        })

    }

}

let hook = new SyncLoopHook(["name"]);
let count = 0;

hook.tap("react", function(name) {
    console.log("react", name)
    return ++count == 3? undefined : "继续学react"
})
hook.tap("node", function(data) {
    console.log("node", data)
    return data
})
hook.tap("vue", function(data) {
    console.log("vue", data)

})

hook.call("xxx")

//react xxx
//node xxx

发布订阅模式基本原理

class Observer {

    constructor() {
        //存放 事件对应的信息
        /**
         * {
         *    eventName1: [
         *      callback1,callback2
         *    ],
         *    eventName2: [
         *      callback_a, callback_b
         *    ] 
         * 
         * }
         */
        this.events = {} //事件中心
    }

    publish(eventName, ...args) { //发布 => 调用事件中心对应的的函数
        if(this.events[eventName]) {
            this.events[eventName].forEach(cb => cb.apply(this,args))
        }
    }

    subscribe(eventName,callback) {// 订阅 => 向事件中心中添加对应的事件
        if(this.events[eventName]) {
            this.events[eventName].push(callback);
        }else {
            this.events[eventName] = [ callback ]
        }
    }

    unSubscribe(eventName, callback) { //取消订阅 => 把对应事件名称对应的函数中
        if(events[eventName]) {
            events[eventName] = events[eventName].filter(cb != callback);
        }
    }


}
let observer = new Observer();
//测试
//先订阅
observer.subscribe("eventOne", function() {
    console.log("我是eventOne的回调函数1")
})
observer.subscribe("eventOne", function() {
    console.log("我是eventOne的回调函数2")
})
observer.subscribe("eventOne", function() {
    console.log("我是eventOne的回调函数3")
})
observer.subscribe("eventTwo", function() {
    console.log("我是eventTwo的回调函数1")
})


//然后发布指定事件,调用相关的回调函数
observer.publish("eventOne");
//我是eventOne的回调函数1
//我是eventOne的回调函数2
//我是eventOne的回调函数3
上一篇 下一篇

猜你喜欢

热点阅读