基本原理

vue中store参数,Vuex插件初始化时会为每一个vue实例添加Vuex.Store实例。Vuex.Store实例存储了state、mutation、action、getter相关数据。通过调用commit、dispatch修改state中的值。同时绑定数据,实现对数据的监听。

//通过Vue的响应式来达到对state数据的监听和getters达到计算属性效果
store._vm = new Vue({ 
    data: {
      $$state: state
    },
    computed
  })

mutation不能使用异步请求

commit (_type, _payload, _options) {
    // check object-style commit
    const {
      type,
      payload,
      options
    } = unifyObjectStyle(_type, _payload, _options) //@doc 统一格式,支持对象风格

    const mutation = { type, payload } //@doc mutation的参数
    const entry = this._mutations[type]
    if (!entry) {
      if (process.env.NODE_ENV !== 'production') {
        console.error(`[vuex] unknown mutation type: ${type}`)
      }
      return
    }
    this._withCommit(() => {
      entry.forEach(function commitIterator (handler) {
        handler(payload)
      })
    })
    this._subscribers.forEach(sub => sub(mutation, this.state))  //@doc 订阅的插件执行

    if (
      process.env.NODE_ENV !== 'production' &&
      options && options.silent
    ) {
      console.warn(
        `[vuex] mutation type: ${type}. Silent option has been removed. ` +
        'Use the filter functionality in the vue-devtools'
      )
    }
  }

因为_withCommit函数没有支持异步回调,如果mutation中执行异步操作,那么插件(_subscribers一般是使用插件的时候使用)中的数据可能不正确。而dispatch采用Promise,所以可以支持回调。

dispatch (_type, _payload) {
    // check object-style dispatch
    const {
      type,
      payload
    } = unifyObjectStyle(_type, _payload)

    const action = { type, payload }
    const entry = this._actions[type]
    if (!entry) {
      if (process.env.NODE_ENV !== 'production') {
        console.error(`[vuex] unknown action type: ${type}`)
      }
      return
    }

    try {
      this._actionSubscribers
        .filter(sub => sub.before)
        .forEach(sub => sub.before(action, this.state))
    } catch (e) {
      if (process.env.NODE_ENV !== 'production') {
        console.warn(`[vuex] error in before action subscribers: `)
        console.error(e)
      }
    }
    //@doc 使用Promise
    const result = entry.length > 1
      ? Promise.all(entry.map(handler => handler(payload)))
      : entry[0](payload)

    return result.then(res => {
      try {
        this._actionSubscribers
          .filter(sub => sub.after)
          .forEach(sub => sub.after(action, this.state))
      } catch (e) {
        if (process.env.NODE_ENV !== 'production') {
          console.warn(`[vuex] error in after action subscribers: `)
          console.error(e)
        }
      }
      return res
    })
  }

源码阅读


xuriliang
245 声望6 粉丝

引用和评论

0 条评论