node 根據事件驅動,那基本都是回撥,最常用的叫釋出訂閱模式,什麼叫釋出訂閱呢?對比觀察者模式,前者是主動地,後者是被動的
//釋出訂閱模式
//將時間放到陣列中,當真的發生時在執行
//let EventEmitter = require(`events`);
let EventEmitter = require(`./EventEmitter`);
let {inherits} = require(`util`);
function Girl(){}
inherits(Girl,EventEmitter);
let girl = new Girl;
let cry = () =>{
console.log(`cry`)
}
let drink = () =>{
console.log(`drink`)
}
girl.on(`one`,cry)
girl.on(`two`,drink)
girl.emit(`two`)
複製程式碼
可以正常輸出1.txt裡面的內容,那麼EventEmitter是如何實現的呢?
EventEmitter實現
EventEmitter骨架
function EventEmitter(){
}
EventEmitter.prototype.on = function(type,callback){
}
EventEmitter.prototype.emit = function(type){
}
module.exports = EventEmitter;
複製程式碼
EventEmitter.on
function EventEmitter(){
this._events = {};
}
//this._events = {one:[cry],two:[drink]}
EventEmitter.prototype.on = function(type,callback){
//如果例項不存在則會建立一個空物件
if(!this._events) this._events = Object.create(null) //繼承會找不到event ,直接例項可以, Cannot read property `one` of undefined 初始化this._events
// this._events ={} 和 this._events = Object.create(null) 的區別 前者原型指標指向object鏈,後者沒有任何屬性,後者可以避免第三方繼承
if(this._events[type]){ // 檢視事件名稱是否存在
this._events[type].push(callback)
}else{
this._events[type] = [callback] //將事件繫結在物件上
}
}
複製程式碼
**EventEmitter.newListener || EventEmitter.addListener **
EventEmitter.addListener = EventEmitter.prototype.on = function(type,callback){
//如果例項不存在則會建立一個空物件
if(!this._events) this._events = Object.create(null)
if(this.newListener && this._events[`newListener`] && this._events[`newListener`].length>0){
if(type != `newListener`){
this._events[`newListener`].forEach(fn => fn(type))
}
}//繼承會找不到event ,直接例項可以, Cannot read property `one` of undefined 初始化this._events
// this._events ={} 和 this._events = Object.create(null) 的區別 前者原型指標指向object鏈,後者沒有任何屬性,後者可以避免第三方繼承
if(this._events[type]){ // 檢視事件名稱是否存在
this._events[type].push(callback)
}else{
this._events[type] = [callback] //將事件繫結在物件上
}
}
複製程式碼
EventEmitter.defaultMaxListeners || emitter.getMaxListeners() || emitter.setMaxListeners()
EventEmitter.defaultMaxListeners = 10; //預設最大監聽數
EventEmitter.prototype.setMaxListeners = function(count){
this._count = count;
}
EventEmitter.prototype.getMaxListeners = function(){
return this._count || EventEmitter.defaultMaxListeners
}
EventEmitter.addListener = EventEmitter.prototype.on = function(type,callback){
...
if(this._events[type].length === this.getMaxListeners()){
console.warn(`memeoy link detected`)
}
}
複製程式碼
EventEmitter.eventNames || listeners
EventEmitter.prototype.eventNames = function(){
return Object.keys(this._events)
}
EventEmitter.prototype.listeners = function(type){
return this._events[type]
}
複製程式碼
removeListener || removeAllListeners
//找到陣列裡的方法對應的移除掉即可
EventEmitter.prototype.removeListener = function(type,callback){
if (typeof callback !== `function`) throw new TypeError(`"callback" argument must be a function`);
if(this._events[type]){
// filter()把傳入的函式依次作用於每個元素,然後根據返回值是true還是false決定保留還是丟棄該元素。
//this._events[type] = this._events[type].filter(fn => fn != callback)
//一次只刪除一個,不是刪除所有相同的type,應該用下面方法
// for(let i = 0;i < this._events[type].length;i++){
// if(this._events[type][i] == callback){
// this._events[type].splice[i]
// break;
// }
// }
//同上效果
this._events[type].splice(this._events[type].indexOf(callback),1)
}
}
EventEmitter.prototype.removeAllListeners = function(type){
if(this._events[type]){
return this._events[type] = Obj.create(null)
}else{
}
}
複製程式碼
EventEmitter.once
EventEmitter.prototype.once = function (type,callback){
//當emit時warp執行需要繼續將引數傳遞給callback
let warp = (...args) =>{
callback(...args);
this.removeListener(type,warp) //用on繫結的時候,在emit的時候執行wap
}
warp.l = callback;//將callback方法掛在到warp屬性上
this.on(type,warp);
}
//在once包了一層wap,我們需要對此wap做細節處理
複製程式碼
emit
EventEmitter.prototype.emit = function(type , ...args){
if(this._events[type]){
this._events[type].forEach(fn => fn(...args));
}else{
this._events = {}
}
}
//找到陣列裡的方法對應的移除掉即可
EventEmitter.prototype.removeListener = function(type,callback){
if (typeof callback !== `function`) throw new TypeError(`"callback" argument must be a function`);
if(this._events[type]){
// filter()把傳入的函式依次作用於每個元素,然後根據返回值是true還是false決定保留還是丟棄該元素。
//this._events[type] = this._events[type].filter(fn =>{
// return fn != callback && fn.l != callback
// })
//一次只刪除一個,不是刪除所有相同的type,應該用下面方法
for(let i = 0;i < this._events[type].length;i++){
if(this._events[type][i] == callback || this._events[type][i].l == callback ){
this._events[type].splice[i]
break;
}
}
//不考慮warp同上效果
//this._events[type].splice(this._events[type].indexOf(callback) ,1)
}
}
複製程式碼
所以現在我們寫出的程式碼總結如下
function EventEmitter(){
this._events = {}
}
//this._events = {one:[cry],two:[drink]}
EventEmitter.prototype.eventNames = function(){
return Object.keys(this._events)
}
EventEmitter.prototype.listeners = function(type){
return this._events[type]
}
EventEmitter.defaultMaxListeners = 10; //預設最大監聽數
EventEmitter.prototype.setMaxListeners = function(count){
this._count = count;
}
EventEmitter.prototype.getMaxListeners = function(){
return this._count || EventEmitter.defaultMaxListeners
}
EventEmitter.addListener = EventEmitter.prototype.on = function(type,callback){
//如果例項不存在則會建立一個空物件
if(!this._events) this._events = Object.create(null) //繼承會找不到event ,直接例項可以, Cannot read property `one` of undefined 初始化this._events
// this._events ={} 和 this._events = Object.create(null) 的區別 前者原型指標指向object鏈,後者沒有任何屬性,後者可以避免第三方繼承
//如果當前不是newListenernewListener方法就需要讓newListener回撥一次執行,傳入類
if(this.newListener && this._events[`newListener`] && this._events[`newListener`].length>0){
if(type != `newListener`){
this._events[`newListener`].forEach(fn => fn(type))
}
}
if(this._events[type]){ // 檢視事件名稱是否存在
this._events[type].push(callback)
}else{
this._events[type] = [callback] //將事件繫結在物件上
}
if(this._events[type].length === this.getMaxListeners()){
console.warn(`memeoy link detected`)
}
}
EventEmitter.prototype.emit = function(type , ...args){
if(this._events[type]){
this._events[type].forEach(fn => fn(...args));
}else{
this._events = {}
}
}
//找到陣列裡的方法對應的移除掉即可
EventEmitter.prototype.removeListener = function(type,callback){
if (typeof callback !== `function`) throw new TypeError(`"callback" argument must be a function`);
if(this._events[type]){
// filter()把傳入的函式依次作用於每個元素,然後根據返回值是true還是false決定保留還是丟棄該元素。
//this._events[type] = this._events[type].filter(fn =>{
// fn != callback && fn.l != callback
// })
//一次只刪除一個,不是刪除所有相同的type,應該用下面方法
for(let i = 0;i < this._events[type].length;i++){
if(this._events[type][i] == callback || this._events[type][i].l == callback ){
this._events[type].splice[i]
break;
}
}
//不考慮warp同上效果
//this._events[type].splice(this._events[type].indexOf(callback) ,1)
}
}
EventEmitter.prototype.removeAllListeners = function(type){
if(this._events[type]){
return this._events[type] = Obj.create(null)
}else{
}
}
EventEmitter.prototype.once = function (type,callback){
//當emit時warp執行需要繼續將引數傳遞給callback
let warp = (...args) =>{
callback(...args);
this.removeListener(type,warp) //用on繫結的時候,在emit的時候執行wap
}
warp.l = callback;//將callback方法掛在到warp屬性上
this.on(type,warp);
}
module.exports = EventEmitter;
複製程式碼
測試程式碼
//釋出訂閱模式
//將時間放到陣列中,當真的發生時在執行
// let EventEmitter = require(`events`);
let EventEmitter = require(`./EventEmitter`);
let {inherits} = require(`util`);
function Girl(){
}
inherits(Girl,EventEmitter);
let girl = new Girl;
let cry = (a,b,c) =>{
console.log(`cry`,a,b,c)
}
let drink = () =>{
console.log(`drink`)
}
girl.on(`newListener`,(type) => {
console.log(type)
})
girl.on(`one`,cry)
girl.on(`one`,drink)
girl.on(`one`,cry)
girl.removeListener(`one`,cry) //找到one把 事件刪掉
girl.emit(`one`,1,2,3);
console.log(girl.eventNames())
console.log(girl.listeners(`one`))
複製程式碼
util使用
我們經常用的util模組(node 8版本以上)
let {promisify,inherits} = require(`util`);
let fs = require(`fs`);
let read = promisify(fs.readFile); //
read(`1.txt`,`utf8`).then(data =>{
console.log(data)
})
//相當於
async function r(){
try{
let result = await read(`1.txt`,`utf8`)
return result;
}catch(e){
throw e;
}
}
r().then(data=>{
console.log(data)
},err=>{console.log(err)})
//koa 後期也是採用 async await
function A(){
}
A.prototype.a = 1;
function B(){
}
inherits(B,A)//b繼承a 之繼承公有方法
let b = new B()
console.log(b.a);
//相當於
B.prototype = Object.create(A.prototype)
//相當於
B.prototype.__proto__ = A.prototype
//相當於
Object.setPrototypeOf(B.prototype,A.prototype)
複製程式碼