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));