事件循环
- 事件: 键盘事件, 其他东西触发的, 统称为事件
- 轮询: 操作系统通过轮询的方式, 每个一段时间就询问事件有没有触发
- JS: 浏览器
console.log(1)
console.log(2)
console.log(3)
// js 是单线程, 发消息告诉 c++ , 轮询 ajax 事件
ajax() // 假如等待事件 1s, -> (操作系统/浏览器/...) 会轮询, 直到事件的发生
// 会继续执行, 不受 ajax 事件影响
console.log(4)
console.log(5)
console.log(6)
- Node.js
node.js EventLoop(事件循环)
的过程
-
- tiemrs -> [setTimeout(fn, 1s)] -> poll
- 第一个阶段不确定有没有执行, 去第二个阶段 (poll) 去等待(执行 js)
- 碰见
setTimeout
直接放入 timer [] - 碰见
setImmediate
立即执行, 放到 check 检查执行 -> 执行完, 去看 timers 的队列 -
setImmediate
是否先执行, 要看 开启eventloop
进入 poll 阶段
-
- poll 停留/等待 -> check
- 事件大部分事件停留在 poll 阶段等待事件,
- check -> setImmediate(fn2, 0) -> timers
process.nextTick()
并不是eventloop
的一部分, 不管event loop
处在哪个阶段,nextTick队列
都是在当前阶段后就被执行了, poll 阶段结束就执行nextTick
, 进入 check 阶段
- check -> setImmediate(fn2, 0) -> timers
setImmediate(() => {
console.log('setImmediate1)
setTimeout(() => {
console.log('setTimeout1)
}, 0)
})
setTimeout(() => {
console.log('setTimeout2)
setImmediate(() => {
console.log('setImmediate2)
})
}, 0)
// 分析 eventloop 阶段
1. timer
2. poll
3. check
上面代码: 第一个 setImmediate 会进入 check 阶段立即执行, 第一个setTimeout 会进入 timer, 放入第一个队列, 然后 第一个 setImmediate 里面的 setTimeout 会被放入 timer 阶段 第二个,
==> 先打印 setImmediate1 -> 然后 打印 setTimeout2 -> 继续 timer 阶段 setTimeout1 -> 最后回到check 阶段 -> setImmediate2
总结
Node.js 的 EventLoop
的几个阶段:timers poll check
, 顺序是: timers -> poll -> check -> timers
- Node.js
-
setTimeout
-> timers 阶段 -
setImmediate
-> check 阶段 -
process.nextTick
-> 当前在哪个阶段的后面: 如果是在check阶段, 就在这个阶段完成后面执行 再到其它阶段,
- chrome
-
setTimeout
-> 宏任务(一会) -
.then(fn)
-> 微任务(马上) -
new Promise(fn)
-> 立即执行, 同步的
继承与组合
类知识简介
- 为什么有类?
- 不同对象的属性重复了, 就有了类
- 为什么有继承
- 不同的类的属性重复了, 就有了继承
// 两个对象属性重复
let person1 = {
name: "yym1",
age: 12,
sayHi() {},
}
let person2 = {
name: "yym2",
age: 18,
sayHi() {},
}
// 使用 class 把上面重复的弄出来, 我们可以创建很多 person
class Person {
name
age
sayHi
constructor(name, age) {
this.name = name
this.age = age
}
}
let person1 = new Person("yym1", 12)
let person2 = new Person("yym2", 18)
// 函数都是共用的?
// 给每个对象自身加一个函数
class Person {
mySayHi = () => {} // 自用
sayHi()
}
let person1 = new Person()
let person2 = new Person()
person1.sayHi === person2.sayHi // true
person1.mySayHi === person2.mySayHi // false
// 箭头函数没有 this, 使用外面的 this
继承
假设我们有两个类 都需要一个功能: 发布订阅功能, 但其他功能不一样, 如果我们每个类都写一个 发布订阅 就有点重复了, 所以我们写个类 只有发布订阅功能
// 发布订阅
class EventEmitter {
constructor() {}
catch = []
on() {}
off() {}
emit() {}
}
class Person extends EventEmitter {
name
constructor(name) {
super()
this.name = name
}
}
class 其他 extends EventEmitter {
name
constructor(name) {
super() // 调用父的方法和属性
this.name = name
}
}
继承的其他功能: 重写
- 子类重写父类的所有属性, 以实现多态
- 多态的意思是不同的子类对同一个消息有不同的反应
class Person extends EventEmitter {
name
constructor(name) {
super()
this.name = name
}
on(eventName, fn) {
console.log('我要监听了)
super.on(eventName, fn)
}
}
继承的问题? 如果需要更多的功能 => 使用组合
组合
你要什么我复制给你,
class Person {
name
sayHi()
}
let person1 = new Person('frank')
mixin(person1, new EventEmitter())
// mixin 简单实现
function mixin(to, form) {
for(let key in from ) {
to[key] = from [key]
}
}
// 需要更多功能
mixin(person1, new EventEmitter())
mixin(person1, new 飞())
mixin(person1, new 杀())
有了组合, 你不需要 class, 直接函数 + 闭包 (后续写篇博客)