Publish and subscribe.

Case study (making a simple player as an example, including concepts, not concrete logic implementation)

The main steps of player:

  1. Initialize the player -> Play -> Playing -> End

Convert to code: (demo1.js)

class Player{
  init(){}
  play(){}
  stop(){}}Copy the code

Some of these steps are too time consuming to be invoked synchronously. For example: initialization. (The play method cannot be called if player initialization is not complete)

Convert to code: (demo2.js)

// Because each step can be a very time-consuming operation.
class Player {
  constructor(){
    this.isInitSuccess = false;
  }
  init() {
    setTimeout(() = > { // Imitate the time-consuming operation, assuming that after two seconds, the player initialization is complete
      this.isInitSuccess = true;
    }, 2000);
  }
  play() {
      if (!this.isInitSuccess) throw Error('Player is initialized')}stop(){}}let player = new Player()
// The code will report an error because init takes time
player.init()
player.play()
Copy the code

How to solve this problem? A publish and subscribe model can be used; Convert to code: (demo3.js)

class Player {
  constructor() {
    // initsuccess
    this.events = {};
    this.isInitSuccess = false;
  }
  init() {
    setTimeout(() = > { // Imitate the time-consuming operation, assuming that after two seconds, the player initialization is complete
      this.isInitSuccess = true;
      this.emit('initsuccess'.' ')},2000); }...on(eventNamve,cb){
    this.events[eventNamve] = (this.events[eventNamve] ? this.events[eventNamve].push(cb) : [cb]); },emit(eventNamve,... args){(this.events[eventNamve] || []).forEach(eventCallBack= > {
          eventCallBack(...args)
        });
  }
}
let player = new Player()
player.init();
player.on('initsuccess'.() = >{
  console.log('Initialization completed')})Copy the code

What is the publish-subscribe model?

In the above code, we registered a function using ON, and the internal emit fires when appropriate. We call the code for this idea the publish and subscribe model. The on method is triggered, which we call ‘subscriber’, and the EMIT method is triggered, which we call ‘publisher’.

Case extension

  1. Added ‘Playing’ and ‘playing Done’ subscribers

Convert to code: (demo4.js)

class Player {
  constructor() {
    this.events = {};// initsuccess
    this.isInitSuccess = false;
    this.timer = null;
    this.time = 10; 
  }
  init() {
    setTimeout(() = > { // Imitate the time-consuming operation, assuming that after two seconds, the player initialization is complete
      this.isInitSuccess = true;
      this.emit('initsuccess'.' ')},2000);
  }
  play() {
    if (!this.isInitSuccess) throw Error('Player is initialized')
    this.time = 10;
    this.timer = setInterval(() = > {
       this.time--;
       if (this.time===0) {clearInterval(this.timer) 
         this.emit('playiend'.' ')}this.emit('playing'.this.time) 
    }, 1000);
  }
  on(eventNamve, cb) {
    this.events[eventNamve] = (this.events[eventNamve] ? this.events[eventNamve].push(cb) : [cb]);
  }
  emit(eventNamve, ... args){(this.events[eventNamve] || []).forEach(eventCallBack= > eventCallBack(...args));
  }
}
let player = new Player()
player.init();
player.on('initsuccess'.() = > {
  console.log('Initialization completed')
  player.play()
});
player.on('playing'.(time) = > {
  console.log('Remaining Playing time',time)
})
player.on('playend'.(time) = > {
  console.log('Play done')})Copy the code

Observer model

The Observer pattern is a simplified application of the publish-subscribe pattern.

See the case

class Subject { // The observed class needs to collect the observer
  constructor(name) {
    this.name = name;
    this.state = 'Very happy'
    this.observers = [];
  }
  attach(o) { // Collect the baby
    this.observers.push(o); // on
  }
  setState(newState) {
    this.state = newState;
    this.observers.forEach(o= > o.update(this.name, newState)) // emit}}class Observer { / / observer
  constructor(name) {
    this.name = name;
  }
  update(s, state) {
    console.log(this.name + ":" + s + 'current'+ state); }}// VUE data changed (state) view to update (notify dependent person)

let s = new Subject('Baby');
let o1 = new Observer('daddy');
let o2 = new Observer('mother');
s.attach(o1)
s.attach(o2)
s.setState('Not happy')
Copy the code

The characteristics of

  1. There is only one subscription event (attach).
  2. Add the concept of state, in this case: the baby’s state (happy, unhappy).
  3. Form a closed loop concept. (The baby is not happy –> notify mom and Dad –> Mom and Dad coax the baby)

Publish/subscribe vs. Observer mode: