1.callback(发布订阅模式、观察者模式)
2020-10-15 本文已影响0人
星星的成长之路
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.发布订阅模式
- 必须先订阅on,才能发布emit;
- 发布和订阅之间有一个媒介this_arr=[],通过媒介进行交互,俩人都不管理,因此可以认为二者是独立的;
- 每次调用订阅on时,都会把传进来的方法push到this_arr中;
- 每次调用发布emit时,需要让this_arr里的方法都执行一遍;
- 订阅就是把方法维护到一个数组里;发布就是数组里的方法依次执行;
- 观察者模式包含发布订阅模式
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('哭了'); // 被观察者更改状态