代码分析


最近在和别的团队合作一个项目。看了别人的代码,感触特别多。代码写的特别优雅。

// flexbridge.js
const FlexBridge = class {
  constructor(){

    //桥接具体实现(自动依赖注入)
    this.bridge = null
    
    // 前端的枚举类型
    this.IOS = "ios"
    this.ANDROID = "android"
    this.UNKNOWN = "unknown"

    this.APP = "app"
    this.H5 = "h5"
    this.WEIXIN = "weixin"
    this.WXXCX = "wxxcx"
    this.QQ = "qq"

    //全局暴露,给静态页面使用
    window["FlexBridge"] = this
  }

  async _(method, args){
    if(this.bridge === null){
      let client = await this.getClientInfo().type
      let bridgeModule = null
      switch (client) {
        // 实现按需加载 根据不同的端 加载对应的实现类
        case this.APP:
          bridgeModule = import( /* webpackChunkName: "bridge-app" */ './bridges/app.js')
          break;
        case this.H5:
          bridgeModule = import( /* webpackChunkName: "bridge-h5" */ './bridges/h5.js')
          break;
        case this.WXXCX:
        case this.WEIXIN:
          bridgeModule = import( /* webpackChunkName: "bridge-weixin" */ './bridges/weixin.js')
          break;
        default:
          throw new Error('Unknown Client')
          break;
      }
    }

    bridgeModule = await bridgeModule

    // 实例化 具体的桥接
    this.bridge = new bridgeModule.default(this)

    // 返回一个promise
    return new Promise((resolve, reject) =>{
      // 如果桥接中有该方法 
      if(method in this.bridge)
        // 把resolve、reject作为入参,和args一起传给bridge的method
        this.bridge[method].call(this.bridge, args, resolve, reject)
      // 如果没有 则抛出异常  
      else
        reject({
          code: 99,
          message: `${method}尚未实现`
        })
    })
  }

  // 获取系统信息
  getOSInfo(){
    let ua = navigator.userAgent
    let type = this.UNKNOWN

    if (/Android|Adr\s|Linux\sU|U\sLinux/i.test(ua))
      type = this.ANDROID
    else if (/iPh(one)?\sOS|iOS/i.test(ua))
      type = this.IOS

    let info = {
      type: type,
      version: "" //todo...
    }

    // 1. 返回立即执行函数
    // 2. 给getOSInfo方法重新赋值为 info
    // 3. 使用闭包 第二次调用就不用再次执行正则的判断了
    return (this.getOSInfo = () => info)()
  }

  // 获取端信息
  getClientInfo(){
    let ua = navigator.userAgent
    let type = this.H5

    if(/xxx/i.test(ua)) {
      type = this.APP
    }
    else if(/MicroMessenger/i.test(ua)) {
      let res = null
      try {
        res = await wx.miniProgram.getEnv()
        if(res && res.miniprogram) {
          type = this.WXXCX
        } 
        else {
          type = this.WEIXIN
        }
      } catch (e) {
        type = this.WEIXIN
      }
    }
    else if (/QQ\//i.test(ua)) {
      type = this.QQ
    }

    let info = {
      type,
      version: "预留字段"
    }

    return (this.getClientInfo = ()=> Promise.resolve(info))()
  }

  // 获取定位信息
  getLocation() { return this._('getLocation', arguments) }

}

export default new FlexBridge()
// main.js
import FlexBridge from "flex-bridge"

Vue.prototype.bridge = FlexBridge

// xxx.vue 用户页面中调用
this.bridge.getLocation({
  needAddress: 1,
  needPoi: 1,
  radius: 1000
}).then(data => {
  console.log(data);
}).catch(error => {
  console.log(error);
})
// h5.js
class H5 = class {
  constructor(flexbridge) {
    this.flexbridge = flexbridge
  }

  getLocation(args, resolve, reject) {
    if('geolocation' in navigator){
      let { needAddress, needPoi, radius, bizType, uuid } = args[0]
      navigator.geolocation.getCurrentPosition(data => {
        let lat = data.coords.latitude
        let lng = data.coords.longitude
        let coordType = 'wgs84'
        if(needAddress === 1){
          // xxx
        }
        else{
          resolve({lat, lng, coordType})
        }
      }, error => {
        if(error.code == error.TIMEOUT){
          this.getLocation({
            enableHighAcuracy: false,
            timeout: 4e3,
            retryed: true
          }, resolve, reject)
        }
        else{
          reject({
            code: 'xx',
            exception: error
          })
        }
      })
    }
    else{
      reject({
        code: 'xx',
        message: 'Not support geolocation'
      })
    }
  }
}

export default H5