发布订阅设计模式
定义:一种一(发布者)对多(订阅者)的依赖关系,发布者发送改变状态后,所有依赖于它的订阅者都会接收到通知,并由调度中心来执行订阅者的内容(订阅函数)。
// 发布订阅模式的实现
class Event{
constructor(){
// 创建调度中心,使用Map提高查找效率
this.listener = new Map();
}
// 注册订阅函数
on(eventName, fn){
if(this.listener.has(eventName)){
this.listener.set(eventName, [...this.listener.get(eventName), fn]);
}else this.listener.set(eventName, [fn]);
}
// 根据事件名称调用响应的订阅函数
emit(eventName, data){
if(this.listener.has(eventName)){
this.listener.get(eventName).forEach(fn =>fn(data));
}
}
off(eventName, fn){
let fncArr = this.listener.get(eventName);
if(!fncArr){
return false;
}
// 没有传入则视为置空
if(!fn){
fncArr = [];
}else{
for(let i=0;i<fncArr.length;i++){
if(fncArr[i] === fn){
fncArr.splice(i,1);
break;
}
}
}
this.listener.set(eventName, fncArr);
}
}
let event = new Event();
let func = () =>{
console.log("error");
}
// 注册订阅函数
event.on("test", (data)=>console.log(data));
event.on("test", func);
// 发布者发送数据,由调度中心执行相应的订阅函数
event.emit("test", "hello"); // hello \n error
// 注销订阅函数
event.off("test", func);
event.emit("test", "new") // new
与观察者模式的区别
- 发布订阅模式中包含了调度中心,解除了发布者与订阅者的耦合性;同时,可以根据不同主题来添加订阅者,管理更加细化。
- 对于观察者模式,可以理解为老师与班级学生的关系,老师布置任务,学生都会被通知执行。
- 对于发布订阅模式,可以理解为语文,数学等老师与班级学生的关系,不同的老师布置任务,学生会收到不同的通知,执行不同的任务。
Event Loop
js是一门单线程语言,其异步与多线程的实现是通过 Event Loop 来实现的。
- 调用栈
- 消息队列(setTimeout、setInterval等的事件回调函数,会在调用栈清空后执行)。
- 微任务队列(Promise,async await等创建的异步操作,会在调用栈清空后立即执行,优先于消息队列)。
var p = new Promise(resolve =>{
console.log(4);
resolve(5);
})
function func1(){
console.log(1);
}
function func2(){
setTimeout(() =>{
console.log(2); // 消息队列
});
func1();
console.log(3);
p.then(x =>{
console.log(x); // 微任务队列 1
}).then(() =>{
console.log(6); // 微任务队列 2
});
}
func2(); // 4 1 3 5 6 2
事件传播机制和事件代理
事件传播机制
一次事件的发生包含了3个过程:
- 事件捕获阶段:从最外层向内查找,构建冒泡阶段需要的传播路线,同时遇到该事件的监听函数就会执行;(父->子)
- 事件处理阶段:执行目标元素的监听函数;
- 事件冒泡阶段:从目标元素上升,检查经过的节点是否注册该事件的监听函数,有则执行。(子->父)
事件捕获与事件冒泡的选择方式:
// flag 为 true 时方法在事件捕获阶段执行。
// false 则方法在事件冒泡阶段执行。
x.addEventListener("name", func, flag)
事件委托
通过事件的冒泡传播机制,可以发现,如果在一个容器的后代元素中,有很多的相同行为都要处理,则只需要在容器中绑定事件行为即可。通过查找链可以进行方法的调用。
浏览器渲染机制步骤简述
- 处理 HTML 标记,构建DOM树;
- 处理CSS标记,构建CSSOM树;
- 将两树融合为渲染树;
- 根据渲染树,在页面进行渲染和解析