js 观察者模式

发布&订阅
一对多
不管是前端还是后端,使用场景最广泛的设计模式,后端的RabbitMQ队列也使用了这种模式

// 主题,接收状态变化,触发每个观察者
class Subject {
    constructor() {
        this.state = 0
        this.observers = []
    }
    getState() {
        return this.state
    }
    setState(state) {
        this.state = state
        this.notifyAllObservers()
    }
    attach(observer) {
        this.observers.push(observer)
    }
    notifyAllObservers() {
        this.observers.forEach(observer => {
            observer.update()
        })
    }
}

// 观察者,等待被触发
class Observer {
    constructor(name, subject) {
        this.name = name
        this.subject = subject
        this.subject.attach(this)
    }
    update() {
        console.log(`${this.name} update, state: ${this.subject.getState()}`)
    }
}

// 测试代码
let s = new Subject()
let o1 = new Observer('o1', s)
let o2 = new Observer('o2', s)
let o3 = new Observer('o3', s)

s.setState(1)
s.setState(2)
s.setState(3)

场景

网页事件绑定

    
    

promise

    function loadImg(src) {
        let p = new Promise(function(resolve, reject) {
            let img = document.createElement('img');
            img.onload = function() {
                resolve(img)
            };
            img.onerror = function() {
                reject('图片加载失败')
            };
            img.src = src;
        })
        return p;
    }
    let src = 'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2054160543,3972664456&fm=26&gp=0.jpg';
    let result = loadImg(src);
    result.then(function(img) {
        console.log('width', img.width);
        document.body.append(img);
        return img;
    }).then(function(img) {
        document.body.append(img);
        console.log('height', img.height);
    })

jQuery Callbacks

    let callbacks = $.Callbacks();
    callbacks.add(function(info) {
        console.log('fn1', info);
    })
    callbacks.add(function(info) {
        console.log('fn2', info);
    })
    callbacks.add(function(info) {
        console.log('fn3', info)
    })
    callbacks.fire('gogogo');
    callbacks.fire('fire');

nodejs自定义事件

const EventEmitter = require('events').EventEmitter;

const emitter1 = new EventEmitter();
emitter1.on('some', () => {
    //监听some事件
    console.log('some event is occured 1');
})
emitter1.on('some', () => {
    //监听some事件
    console.log('some event is occured 2');
})

emitter1.emit('some');
//Stream 用到了自定义事件
let fs = require('fs');
let readStream = fs.createReadStream('./data/file.txt');

let length = 0;
readStream.on('data', function(chunk) {
    length += chunk.toString().length;
})
readStream.on('end', function() {
    console.log(length);
})
//readline 用到了自定义事件
let readline = require('readline');
let fs = require('fs');

let rl = readline.createInterface({
    input: fs.createReadStream('./data/file.txt')
})

let linenum = 0;
rl.on('line', function(line) {
    linenum++
})
rl.on('close', function() {
    console.log('linenum', linenum)
})

其他场景

  • nodejs中:处理http请求、多进程通讯
  • vue和react组件生命周期触发
  • vue watch

设计原则

  • 主题和观察者分离,不是主动触发而是被动监听,2者解耦
  • 符合开闭原则

你可能感兴趣的:(js 观察者模式)