中间件和插件的实现

1.vue的install实现
核心是原型上添加方法/属性

class Store {
  static use (plugin, options) {
    plugin(this, options)
    return this
  }
}

const plugin1 = function (Store) {
  Store.prototype.$someFn1 = function () {}
}

const plugin2 = function (Store, options) {
  Store.prototype.$someFn2 = function () {}
}


Store.use(plugin1).use(plugin2, {})

2.koa的洋葱模式中间件实现
核心是实现一个dispath方法, 这个方法会递归调用中间件, 将下个中间件作为参数next传入上个中间件


const applyApp = ctx => async (...middleware) => {

  async function dispatch(index) {
    let fn = middleware[index]
    if (index === middleware.length) return
    await fn(ctx, () => dispatch(index + 1))
  }
  await dispatch(0)
}

const a1 = async (ctx, next) => {
  ctx.ctxProp += '1'
  console.log('进入1')
  await sleep(2000)
  await next()
  console.log('出去1')
}
const a2 = async (ctx, next) => {
  ctx.ctxProp += '2'
  console.log('进入2')
  await next( + 'C')
  console.log('出去2')
}
const a3 = async (ctx, next) => {
  ctx.ctxProp += '3'
  console.log('进入3')
  await next()
  console.log('出去3')
}

const store = { ctxProp: '' }

applyApp(store)(a1, a2, a3)
.then((v) => {
  console.log(store)
})
.catch(err => console.log(err))
  1. 借助tapale实现hook插件
const {
  SyncHook
 } = require("tapable");


// 一个插件, 在store中注册created/destory生命周期回调, 原型添加一个destory方法
 const somePlugin = function (pluginApi, options) {

  pluginApi.onHook('created', (instance) => {
    console.log('created', instance.status)
  })

  pluginApi.onHook('destory', () => {
    console.log('destory')
  })

  pluginApi.addMethod('destory', () => {
    pluginApi.callHook('destory')
  })

}


const config = {
  plugins: [somePlugin]
}


class Store {
 Hooks = {
   created: new SyncHook(['instance'])
 }
 status = ''
 constructor () {
   this.loadPlugin()
   this.Hooks.created.call(this)
 }
 loadPlugin () {
   config.plugins.map(plugin => plugin(new PluginApi(this)));
 }
}

// 提取的plugin管理api, 提供注册/触发Hook, 原型添加方法
 class PluginApi {
  constructor (store) {
    this.store = store
  }

  onHook (name, handler) {
    if (!this.store.Hooks[name]) {
      this.store.Hooks[name] = new SyncHook();
    }
    this.store.Hooks[name].tap(name, handler)
  }
  callHook (name) {
    this.store.Hooks[name].call()
  }
  addMethod (name, fn) {
    this.store.__proto__[name] = fn
  }
 }



const store = new Store()

setTimeout(() => {
  store.destory()
}, 1000)
posted @ 2022-09-22 14:30  ABC君  阅读(48)  评论(0编辑  收藏  举报