DVA 源码分析

NPM相关资源包: dva, dva-core, redux-saga,  redux

dva-core/createStore

const app = dva()

app.model()

在app启动前app.model方法将model准备好之后存入_models对象中

  function model(m) {
    if (process.env.NODE_ENV !== 'production') {
      (0, _checkModel.default)(m, app._models);
    }
    var prefixedModel = (0, _prefixNamespace.default)((0, _objectSpread2.default)({}, m));
    app._models.push(prefixedModel);
    return prefixedModel;
  }

在app启动后app.model方法会将model准备好之后存入_models后再执行saga步骤

  function injectModel(createReducer, onError, unlisteners, m) {
    m = model(m);
    var store = app._store;
    store.asyncReducers[m.namespace] = (0, _getReducer.default)(m.reducers, m.state, plugin._handleActions);
    store.replaceReducer(createReducer());
    if (m.effects) {
      store.runSaga(app._getSaga(m.effects, m, onError, plugin.get('onEffect')));
    }
    if (m.subscriptions) {
      unlisteners[m.namespace] = (0, _subscription.run)(m.subscriptions, m, app, onError);
    }
  }

app.start()

启动dva-core中的start继而启动saga步骤

var task = (0, _proc2.default)(iterator, subscribe, (0, _utils.wrapSagaDispatch)(dispatch), getState, context, { sagaMonitor: sagaMonitor, logger: logger, onError: onError }, effectId, saga.name);

调用proc模块执行逻辑

try {
      var result = void 0;
      if (isErr) {
        result = iterator.throw(arg);
      } else if (arg === TASK_CANCEL) {
        /**
          getting TASK_CANCEL automatically cancels the main task
          We can get this value here
           - By cancelling the parent task manually
          - By joining a Cancelled task
        **/
        mainTask.isCancelled = true;
        /**
          Cancels the current effect; this will propagate the cancellation down to any called tasks
        **/
        next.cancel();
        /**
          If this Generator has a `return` method then invokes it
          This will jump to the finally block
        **/
        result = _utils.is.func(iterator.return) ? iterator.return(TASK_CANCEL) : { done: true, value: TASK_CANCEL };
      } else if (arg === CHANNEL_END) {
        // We get CHANNEL_END by taking from a channel that ended using `take` (and not `takem` used to trap End of channels)
        result = _utils.is.func(iterator.return) ? iterator.return() : { done: true };
      } else {
        result = iterator.next(arg);
      }

      if (!result.done) {
        // console.log(result.value)
        runEffect(result.value, parentEffectId, '', next);
      } else {
        /**
          This Generator has ended, terminate the main task and notify the fork queue
        **/
        mainTask.isMainRunning = false;
        mainTask.cont && mainTask.cont(result.value);
      }
    } catch (error) {
      if (mainTask.isCancelled) {
        logError(error);
      }
      mainTask.isMainRunning = false;
      mainTask.cont(error, true);
    }

Generator 函数走一步开结果,假设还没完成就走runEffect(result.value, parentEffectId, '', next);

在runEffect方法中根据传了result.value的值也可以说是effect的值

(data = _io.asEffect.take(effect))

来确定下一步执行

      runParallelEffect(effect, effectId, currCb) : (data = _io.asEffect.take(effect)) ? 
      runTakeEffect(data, currCb) : (data = _io.asEffect.put(effect)) ? 
      runPutEffect(data, currCb) : (data = _io.asEffect.all(effect)) ? 
      runAllEffect(data, effectId, currCb) : (data = _io.asEffect.race(effect)) ? 
      runRaceEffect(data, effectId, currCb) : (data = _io.asEffect.call(effect)) ? 
      runCallEffect(data, effectId, currCb) : (data = _io.asEffect.cps(effect)) ? 
      runCPSEffect(data, currCb) : (data = _io.asEffect.fork(effect)) ? 
      runForkEffect(data, effectId, currCb) : (data = _io.asEffect.join(effect)) ? 
      runJoinEffect(data, currCb) : (data = _io.asEffect.cancel(effect)) ? 
      runCancelEffect(data, currCb) : (data = _io.asEffect.select(effect)) ? 
      runSelectEffect(data, currCb) : (data = _io.asEffect.actionChannel(effect)) ? 
      runChannelEffect(data, currCb) : (data = _io.asEffect.flush(effect)) ? 
      runFlushEffect(data, currCb) : (data = _io.asEffect.cancelled(effect)) ? 
      runCancelledEffect(data, currCb) : (data = _io.asEffect.getContext(effect)) ? 
      runGetContextEffect(data, currCb) : (data = _io.asEffect.setContext(effect)) ? 
      runSetContextEffect(data, currCb) : /* anything else returned as is */currCb(effect)

初始化的时候会执行runTakeEffect开启channel监听:

  function runTakeEffect(_ref2, cb) {
    var channel = _ref2.channel,
        pattern = _ref2.pattern,
        maybe = _ref2.maybe;

    channel = channel || stdChannel;
    var takeCb = function takeCb(inp) {
      return inp instanceof Error ? cb(inp, true) : (0, _channel.isEnd)(inp) && !maybe ? cb(CHANNEL_END) : cb(inp);
    };
    try {
      channel.take(takeCb, matcher(pattern));
    } catch (err) {
      return cb(err, true);
    }
    cb.cancel = takeCb.cancel;
  }

启动saga步骤之前会先包装被启动的saga:

store.runSaga(app._getSaga(m.effects, m, onError, plugin.get('onEffect')));
//或者
sagas.push(app._getSaga(m.effects, m, onError, plugin.get('onEffect')));
sagas.forEach(sagaMiddleware.run)

getSaga.js应该是被babel transform回去的generator函数代码,复杂

应该是将所有的effects添加takeEffect以准备后期的dispatch调用:

如果是generator步骤还没完成或者effects中有这个key就将其启动 watcher:

watcher = getWatcher(key, effects[key], model, onError, onEffect);
        _regenerator.default.mark(function _callee6() {
          return _regenerator.default.wrap(function _callee6$(_context7) {
            while (1) {
              switch (_context7.prev = _context7.next) {
                case 0:
                  _context7.next = 2;
                  return (0, _sagaHelpers.takeEveryHelper)(key, sagaWithOnEffect);

                case 2:
                case "end":
                  return _context7.stop();
              }
            }
          }, _callee6, this);
        })
return (0, _fsmIterator2.default)({
    q1: function q1() {
      return ['q2', yTake, setAction];
    },
    q2: function q2() {
      return action === _channel.END ? [_fsmIterator.qEnd] : ['q1', yFork(action)];
    }
  }, 'q1', 'takeEvery(' + (0, _fsmIterator.safeName)(patternOrChannel) + ', ' + worker.name + ')');

var yTake = { done: false, value: (0, _io.take)(patternOrChannel) };

var action = void 0,
      setAction = function setAction(ac) {
    return action = ac;
  };
function take() {
  var patternOrChannel = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '*';

  if (arguments.length) {
    (0, _utils.check)(arguments[0], _utils.is.notUndef, 'take(patternOrChannel): patternOrChannel is undefined');
  }
  if (_utils.is.pattern(patternOrChannel)) {
    return effect(TAKE, { pattern: patternOrChannel });
  }
  if (_utils.is.channel(patternOrChannel)) {
    return effect(TAKE, { channel: patternOrChannel });
  }
  throw new Error('take(patternOrChannel): argument ' + String(patternOrChannel) + ' is not valid channel or a valid pattern');
}

最后在将watcher交给saga

sagaEffects.fork(watcher)

初始化完成以后在调用dispatch 方法的时候会执行并且在subscribers 中执行该action

    return function (next) {
      return function (action) {
        if (sagaMonitor && sagaMonitor.actionDispatched) {
          console.log('middleware 70')
          sagaMonitor.actionDispatched(action);
        }
        console.log(next)
        console.log(action)
        
        var result = next(action); // hit reducers
        sagaEmitter.emit(action);
        return result;
      };
    };

  function emit(item) {
    console.log('channel 38')
    var arr = subscribers.slice();
    // console.log(subscribers)
    for (var i = 0, len = arr.length; i < len; i++) {
      console.log(arr[i])
      arr[i](item);
    }
  }

将方法emit到监听stdchannel,从而执行,在一开始初始化runsaga的时候会将action放入subscribers

  function subscribe(sub) {
    subscribers.push(sub);
    console.log('channel 31')
    console.log(subscribers)
    return function () {
      return (0, _utils.remove)(subscribers, sub);
    };
  }
    
sagaMiddleware.run = _runSaga.runSaga.bind(null, {
      context: context,
      subscribe: sagaEmitter.subscribe,
      dispatch: dispatch,
      getState: getState,
      sagaMonitor: sagaMonitor,
      logger: logger,
      onError: onError
    });


var task = (0, _proc2.default)(iterator, subscribe, (0, _utils.wrapSagaDispatch)(dispatch), getState, context, { sagaMonitor: sagaMonitor, logger: logger, onError: onError }, effectId, saga.name);

 var stdChannel = (0, _channel.stdChannel)(subscribe);

  var unsubscribe = subscribe(function (input) {
    if (isEnd(input)) {
      close();
      return;
    }
    if (matcher && !matcher(input)) {
      return;
    }
    chan.put(input);
  });

channel.take(takeCb, matcher(pattern));

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值