1.callback(发布订阅模式、观察者模式)

1.前期准备

node 10.0以上
安装vscode和以下插件:

  • live server 通过localhost启动浏览器
  • code runner 可以运行部分代码

2.高阶函数(aop、偏函数、函数柯里化)

一个函数的参数是函数,或者函数的返回值是函数

2.1 aop 面向切片编程(装饰器、前端埋点)

2.2 before方法

// 装饰器  前端埋点 在ajax 的请求中包装一层自己的逻辑
// 判断this是谁 就看调用时. 前面是谁this就是谁
Function.prototype.before = function (callback) {
  let self = this;
  return function () {
    // 这个函数中的this指的是 newFn()前面的this
    callback(); // before 的参数
    console.log(this);
    self.apply(self, arguments);
  };
};
function fn(val) {
  console.log('一定的功能' + val);
}
let newFn = fn.before(function () {
  console.log('在函数执行前执行');
});
newFn('你好');

2.3 after方法:

// lodash debounce throttle
function after(times, callback) {
  // 满足一个特点就是高阶函数 redux
  return function () {
    // Promise.all
    if (--times === 0) {
      callback();
    }
  };
}

// 高阶函数
let newFn = after(2, function () {  
  console.log('after'); 
});
newFn();
newFn();

2.4 并发调用接口,可以用计数器

  • 串行 两个人有关系 上一个人的输出是下一个人的输入
  • 并行 两个人没关系 可以一期执行
// 并发调用接口  两个ajax  ajax1 => name  ajax2 => age  = name+age
let fs = require('fs');
fs.readFile('./name.txt', 'utf-8', function (err, data) {
  if (err) return console.log(err);
  newFn3('name', data);
});
fs.readFile('./age.txt', 'utf-8', function (err, data) {
  if (err) return console.log(err);
  newFn3('age', data);
});

let after = function (times, cb) {
  let res = {};
  return function (key, value) {
    res[key] = value;
    if (--times === 0) {
      cb(res);
    }
  };
};

//这个方法 会在所有异步执行之后执行
let newFn3 = after(2, function (res) {
  console.log(res);
});

3.发布订阅模式

  1. 必须先订阅on,才能发布emit;
  2. 发布和订阅之间有一个媒介this_arr=[],通过媒介进行交互,俩人都不管理,因此可以认为二者是独立的;
  3. 每次调用订阅on时,都会把传进来的方法push到this_arr中;
  4. 每次调用发布emit时,需要让this_arr里的方法都执行一遍;
  5. 订阅就是把方法维护到一个数组里;发布就是数组里的方法依次执行;
  6. 观察者模式包含发布订阅模式
let fs = require('fs');
function EventEmitter() {
  this._arr = [];  // [on1, on2 ...]
}
EventEmitter.prototype.on = function (cb) {
  this._arr.push(cb);
};
EventEmitter.prototype.emit = function () {
  this._arr.forEach((fn) => fn.apply(this, arguments));
};

fs.readFile('./name.txt', 'utf-8', function (err, data) {
  if (err) return console.log(err);
  e.emit('name', data);
});

fs.readFile('./age.txt', 'utf-8', function (err, data) {
  if (err) return console.log(err);
  e.emit('age', data);
});

let e = new EventEmitter();
let obj = {};
e.on(function (key, value) {
  obj[key] = value;
  if (Object.keys(obj).length === 2) {
    console.log(obj);
  }
});


4.观察者模式和发布订阅模式的区别
基于发布订阅模式,但是发布和订阅,两者之间有关系;
发布订阅模式,发布和订阅之间没有关系;

5.观察者模式
观察者Observer;被观察者Subject

  • 被观察者里面应该存放着所有的观察者
  • 被观察者利用attach来装载观察者
  • 被观察者可以自己更新状态且通知自己的观察者
  • 观察者里面有自己的update方法来接受状态变化
// 观察者模式  基于发布订阅模式
// 发布订阅 发布和订阅 两者无关
// 观察者模式 观察者 和 被观察者
// 被观察者 应该存放着观察者 我家有个小宝宝 有一个状态
// 被观察者状态变化 要更新自己身上的所有的观察者
// 被观察者
class Subject {
  constructor() {
    this.name = '小宝宝';
    this.state = '开心';
    this.arr = [];
  }
  attach(observer) {
    this.arr.push(observer); // 用来装载观察者
  }
  setState(newState) {
    this.state = newState; // 更新状态值
    this.arr.forEach((observer) => observer.update(newState)); // 通知自己所有的观察者
  }
}

// 观察者
class Observer {
  constructor(who) {
    this.who = who;
  }
  update(newState) {
    console.log(this.who + '! 小宝宝' + newState); // 接受新的状态
  }
}

let subject = new Subject('小宝宝');
let observer1 = new Observer('爸爸');
let observer2 = new Observer('妈妈');

subject.attach(observer1); // 注册观察者
subject.attach(observer2);

subject.setState('哭了'); // 被观察者更改状态

你可能感兴趣的:(1.callback(发布订阅模式、观察者模式))