reflux-core源码
1.index.js
const version = {
"reflux-core": "@VERSION"
};
// 用户设置createAction返回对象中待添加的方法,创建实例时不可被重复设置,通过闭包存储数据
// 且须保证方法名没有跟PublisherMethods中的方法名起冲突,preEmit、shouldEmit方法除外
import * as ActionMethods from "./ActionMethods";
// action、store扩展为事件对象
import * as ListenerMethods from "./ListenerMethods";
// store向listenable绑定函数,listenable触发事件时执行
import * as PublisherMethods from "./PublisherMethods";
// 用户设置store原型中待添加的方法,创建实例时不可被重复设置,通过闭包存储数据
// 且须保证方法名没有跟PublisherMethods、ListenerMethods中的方法名起冲突,preEmit、shouldEmit方法除外
import * as StoreMethods from "./StoreMethods";
import { staticJoinCreator as maker} from "./joins";
const joinTrailing = maker("last");
const all = joinTrailing; // Reflux.all alias for backward compatibility
const joinLeading = maker("first");
const joinStrict = maker("strict");
const joinConcat = maker("all");
// 工具函数
import * as _ from "./utils";
const utils = _;
// createAction工厂函数,构建仿函数functor,调用functor触发绑定事件
// functor上挂载listen、trigger、triggerAsync、deferWith方法
import {createAction} from "./createAction";
// 多个事件对象的相互监听、触发事件
import {createStore} from "./createStore";
// 创建多个action仿函数对象,对象形式返回
const createActions = (function() {
var reducer = function(definitions, actions) {
Object.keys(definitions).forEach(function(actionName) {
var val = definitions[actionName];
actions[actionName] = createAction(val);
});
};
return function(definitions) {
var actions = {};
if (definitions instanceof Array) {
definitions.forEach(function(val) {
if (_.isObject(val)) {
reducer(val, actions);
} else {
actions[val] = createAction(val);
}
});
} else {
reducer(definitions, actions);
}
return actions;
};
})();
/**
* Sets the eventmitter that Reflux uses
*/
function setEventEmitter (ctx) {
_.EventEmitter = ctx;
}
/**
* Sets the method used for deferring actions and stores
*/
function nextTick (nextTick) {
_.nextTick = nextTick;
}
function use (pluginCb) {
pluginCb(this);
}
// 记录及操作已添加的action、store
import * as __keep from "./Keep";
// export in format that supports syntax: var Reflux = require('reflux-core');
export {
version,
ActionMethods,
ListenerMethods,
PublisherMethods,
StoreMethods,
utils,
createAction,
createStore,
createActions,
setEventEmitter,
nextTick,
use,
joinTrailing,
all,
joinLeading,
joinStrict,
joinConcat,
__keep
};
/*eslint-enable no-underscore-dangle*/
// export in format that supports syntax: import Reflux from 'reflux-core';
Object.defineProperty(exports, "default", {
get: function() {
return exports;
}
});
// 不支持bind方法时,错误提示
if (!Function.prototype.bind) {
console.error(
"Function.prototype.bind not available. " +
"ES5 shim required. " +
"https://github.com/spoike/refluxjs#es5"
);
}2.createAction.js
import * as _ from "./utils";
import * as ActionMethods from "./ActionMethods";
import * as PublisherMethods from "./PublisherMethods";
import * as Keep from "./Keep";
var allowed = { preEmit: 1, shouldEmit: 1 };
// 创建仿函数functor,参数definition中的属性和方法用于构建functor的属性和方法
// 同时functor拥有PublisherMethods中的listen、trigger、triggerAsync、deferWith方法
// 子action通过definition.children添加,asyncResult为真时有["completed", "failed"]两个子action
export function createAction(definition) {
definition = definition || {};
if (!_.isObject(definition)){
definition = {actionName: definition};
}
// 校验ActionMethods中的方法没有跟PublisherMethods中的方法起冲突,preEmit、shouldEmit方法除外
for(var a in ActionMethods){
if (!allowed[a] && PublisherMethods[a]) {
throw new Error("Cannot override API method " + a +
" in Reflux.ActionMethods. Use another method name or override it on Reflux.PublisherMethods instead."
);
}
}
// 校验createAction传参中的方法没有跟PublisherMethods中的方法起冲突,preEmit、shouldEmit方法除外
for(var d in definition){
if (!allowed[d] && PublisherMethods[d]) {
throw new Error("Cannot override API method " + d +
" in action creation. Use another method name or override it on Reflux.PublisherMethods instead."
);
}
}
// childActions以子action名作为键,子action仿函数作为值
definition.children = definition.children || [];
if (definition.asyncResult){
definition.children = definition.children.concat(["completed", "failed"]);
}
var i = 0, childActions = {};
for (; i < definition.children.length; i++) {
var name = definition.children[i];
childActions[name] = createAction(name);
}
// 将PublisherMethods、ActionMethods、definition中的属性和方法赋予context,最终赋给functor
// 仿函数functor的意义是派发、触发事件
var context = _.extend({
eventLabel: "action",
emitter: new _.EventEmitter(),
_isAction: true
}, PublisherMethods, ActionMethods, definition);
// 直接调用仿函数将使用通过PublisherMethods注入的trggier同步触发、triggerAsync异步触发方法
var functor = function() {
var triggerType = functor.sync ? "trigger" : "triggerAsync";
return functor[triggerType].apply(functor, arguments);
};
_.extend(functor, childActions, context);
// 将仿函数functor添加到createdActions中,同时index.js模块中为Reflux提供createdActions的引用
Keep.addAction(functor);
return functor;
}3.PublisherMethods.js
import * as _ from "./utils";
/**
* A module of methods for object that you want to be able to listen to.
* This module is consumed by `createStore` and `createAction`
*/
// 钩子事件,为shouldEmit钩子函数提供参数
// 返回undefined时,shouldEmit方法参数为trigger方法的传参
export var preEmit = function() {};
// 钩子事件,触发事件前校验触发条件是否达成
export var shouldEmit = function() { return true; };
// 通过event-emitter创建的事件对象this.emitter中添加绑定函数,需要修改函数上下文
// 返回撤销绑定函数的执行函数,aborted标记为真
export var listen = function(callback, bindContext) {
bindContext = bindContext || this;
var eventHandler = function(args) {
if (aborted){
return;
}
callback.apply(bindContext, args);
}, me = this, aborted = false;
this.emitter.addListener(this.eventLabel, eventHandler);
return function() {
aborted = true;
me.emitter.removeListener(me.eventLabel, eventHandler);
};
};
// 触发事件,触发事件前执行钩子函数this.preEmit及this.shouldEmit
// this.preEmit为this.shouldEmit提供参数,this.shouldEmit的返回值作为是否触发事件的凭据
export var trigger = function() {
var args = arguments,
pre = this.preEmit.apply(this, args);
args = pre === undefined ? args : _.isArguments(pre) ? pre : [].concat(pre);
if (this.shouldEmit.apply(this, args)) {
this.emitter.emit(this.eventLabel, args);
}
};
export var triggerAsync = function(){
var args = arguments, me = this;
_.nextTick(function() {
me.trigger.apply(me, args);
});
};
// 使用callback装饰之前的trigger函数,返回新的trigger函数
export var deferWith = function(callback) {
var oldTrigger = this.trigger,
ctx = this,
resolver = function() {
oldTrigger.apply(ctx, arguments);
};
this.trigger = function() {
callback.apply(ctx, [resolver].concat([].splice.call(arguments, 0)));
};
};4.createStore.js
import * as _ from "./utils";
import * as Keep from "./Keep";
import {mix as mixer} from "./mixer";
import {bindMethods} from "./bindMethods";
import * as StoreMethods from "./StoreMethods";
import * as PublisherMethods from "./PublisherMethods";
import * as ListenerMethods from "./ListenerMethods";
var allowed = { preEmit: 1, shouldEmit: 1 };
// 仿照react,参数用于配置构造函数,最终生成实例并返回
export function createStore(definition) {
definition = definition || {};
// 校验StoreMethods中的方法没有跟PublisherMethods、ListenerMethods中的方法起冲突,preEmit、shouldEmit方法除外
for(var a in StoreMethods){
if (!allowed[a] && (PublisherMethods[a] || ListenerMethods[a])){
throw new Error("Cannot override API method " + a +
" in Reflux.StoreMethods. Use another method name or override it on Reflux.PublisherMethods / Reflux.ListenerMethods instead."
);
}
}
// 校验definition中的方法没有跟PublisherMethods、ListenerMethods中的方法起冲突,preEmit、shouldEmit方法除外
for(var d in definition){
if (!allowed[d] && (PublisherMethods[d] || ListenerMethods[d])){
throw new Error("Cannot override API method " + d +
" in store creation. Use another method name or override it on Reflux.PublisherMethods / Reflux.ListenerMethods instead."
);
}
}
// 类似react的mixins,多个init、preEmit、shouldEmit或其他mixins中方法均将执行
definition = mixer(definition);
function Store() {
var i = 0, arr;
this.subscriptions = [];
this.emitter = new _.EventEmitter();
this.eventLabel = "change";
// 配置definition的方法执行上下文更正为store
bindMethods(this, definition);
if (this.init && _.isFunction(this.init)) {
this.init();
}
// this.listenables以action相关对象作为项的数组,action名作为键,createAction返回值仿函数作为值
// action作为事件对象,同时获取事件名,绑定函数为store中的方法
if (this.listenables){
arr = [].concat(this.listenables);
for(; i < arr.length; i++){
this.listenToMany(arr[i]);
}
}
}
// Store构造函数原型预先添加方法,再创建实例
// ListenerMethods注入hasListener、listenToMany、listenTo、stopListeningTo、stopListeningToAll方法
// 意义是向关联的action仿函数对象或另一个store实例绑定、解绑事件
// PublisherMethods注入listen绑定事件、trigger触发事件、triggerAsync、deferWith装饰触发方法
_.extend(Store.prototype, ListenerMethods, PublisherMethods, StoreMethods, definition);
var store = new Store();
// 将仿函数functor添加到createdStores中,同时index.js模块中为Reflux提供createdStores的引用
Keep.addStore(store);
return store;
}5.listenerMethods.js
import * as _ from "./utils";
import { instanceJoinCreator as maker } from "./joins";
// 获取listenable仿函数对象下的子仿函数对象,返回值为对象形式
var mapChildListenables = function(listenable) {
var i = 0, children = {}, childName;
for (;i < (listenable.children || []).length; ++i) {
childName = listenable.children[i];
if(listenable[childName]){
children[childName] = listenable[childName];
}
}
return children;
};
// 扁平化多个嵌套的action
// 键值对记录仿函数对象及子仿函数对象,子仿函数对象为驼峰式action名+子action名
var flattenListenables = function(listenables) {
var flattened = {};
for(var key in listenables){
var listenable = listenables[key];// 通过createAction创建的functor仿函数对象
var childMap = mapChildListenables(listenable);
var children = flattenListenables(childMap);
flattened[key] = listenable;
for(var childKey in children){
var childListenable = children[childKey];
flattened[key + _.capitalize(childKey)] = childListenable;
}
}
return flattened;
};
export var hasListener = function(listenable) {
var i = 0, j, listener, listenables;
for (;i < (this.subscriptions || []).length; ++i) {
listenables = [].concat(this.subscriptions[i].listenable);
for (j = 0; j < listenables.length; j++){
listener = listenables[j];
if (listener === listenable || listener.hasListener && listener.hasListener(listenable)) {
return true;
}
}
}
return false;
};
// 向多个action绑定事件
export var listenToMany = function(listenables){
var allListenables = flattenListenables(listenables);
for(var key in allListenables){
var cbname = _.callbackName(key),// "on"+key
localname = this[cbname] ? cbname : this[key] ? key : undefined;// 绑定函数方法名,对应store中的同名方法
if (localname){
// allListenables[key]为通过createAction创建的functor仿函数对象,用以绑定、触发事件
this.listenTo(allListenables[key], localname, this[cbname + "Default"] || this[localname + "Default"] || localname);
}
}
};
// 校验listenable,可能是store实例或action仿函数对象,不能形成循环绑定事件、须有listen方法
export var validateListening = function(listenable){
if (listenable === this) {
return "Listener is not able to listen to itself";
}
if (!_.isFunction(listenable.listen)) {
return listenable + " is missing a listen method";
}
if (listenable.hasListener && listenable.hasListener(this)) {
return "Listener cannot listen to this listenable because of circular loop";
}
};
// 绑定事件
export var listenTo = function(listenable, callback, defaultCallback) {
var desub, unsubscriber, subscriptionobj,
subs = this.subscriptions = this.subscriptions || [];
_.throwIf(this.validateListening(listenable));
// 触发listenable的getInitialState方法,紧接着触发defaultCallback,处理当前store实例
this.fetchInitialState(listenable, defaultCallback);
desub = listenable.listen(this[callback] || callback, this);
// 解绑事件
unsubscriber = function() {
var index = subs.indexOf(subscriptionobj);
_.throwIf(index === -1, "Tried to remove listen already gone from subscriptions list!");
subs.splice(index, 1);
desub();
};
subscriptionobj = {
stop: unsubscriber,
listenable: listenable
};
// this.subscriptions存储解绑事件的函数、以及绑定的listenable
subs.push(subscriptionobj);
return subscriptionobj;
};
// 根据listenable解绑事件
export var stopListeningTo = function(listenable){
var sub, i = 0, subs = this.subscriptions || [];
for(;i < subs.length; i++){
sub = subs[i];
if (sub.listenable === listenable){
sub.stop();
_.throwIf(subs.indexOf(sub) !== -1, "Failed to remove listen from subscriptions list!");
return true;
}
}
return false;
};
// 解绑所有事件
export var stopListeningToAll = function(){
var remaining, subs = this.subscriptions || [];
while((remaining = subs.length)){
subs[0].stop();
_.throwIf(subs.length !== remaining - 1, "Failed to remove listen from subscriptions list!");
}
};
// 当store A监听store B时,store B中含getInitialState
// defaultCallback回调将使store A获取store B的getInitialState情状进行后续操作
export var fetchInitialState = function(listenable, defaultCallback) {
defaultCallback = (defaultCallback && this[defaultCallback]) || defaultCallback;
var me = this;
if (_.isFunction(defaultCallback) && _.isFunction(listenable.getInitialState)) {
var data = listenable.getInitialState();
if (data && _.isFunction(data.then)) {
data.then(function() {
defaultCallback.apply(me, arguments);
});
} else {
defaultCallback.call(this, data);
}
}
};
// joinTrailing( listenables...,callback)
// 多个监听器构成的组合事件中,若单个监听器的事件触发多次时,回调中传参取该监听器接收的第一个参数
export var joinTrailing = maker("last");
// 多个监听器构成的组合事件中,若单个监听器的事件触发多次时,回调中传参取该监听器接收的第一个参数
export var joinLeading = maker("first");
// 多个监听器构成的组合事件中,若单个监听器的事件触发多次时,回调中传参取该监听器接收的所有参数
export var joinConcat = maker("all");
// 多个监听器构成的组合事件中,单个监听器的事件只能触发一次
export var joinStrict = maker("strict");6.joins.js
/**
* Internal module used to create static and instance join methods
*/
import {createStore} from "./createStore";
import * as _ from "./utils";
var slice = Array.prototype.slice,
strategyMethodNames = {
strict: "joinStrict",
first: "joinLeading",
last: "joinTrailing",
all: "joinConcat"
};
/**
* Used in `index.js` to create the static join methods
* @param {String} strategy Which strategy to use when tracking listenable trigger arguments
* @returns {Function} A static function which returns a store with a join listen on the given listenables using the given strategy
*/
export function staticJoinCreator(strategy){
return function(/* listenables... */) {
var listenables = slice.call(arguments);
return createStore({
init: function(){
this[strategyMethodNames[strategy]].apply(this, listenables.concat("triggerAsync"));
}
});
};
}
// 多个listenables绑定组合事件
export function instanceJoinCreator(strategy){
return function(/* listenables..., callback*/){
_.throwIf(arguments.length < 2, "Cannot create a join with less than 2 listenables!");
var listenables = slice.call(arguments),
callback = listenables.pop(),
numberOfListenables = listenables.length,
join = {
numberOfListenables: numberOfListenables,
callback: this[callback] || callback,
listener: this,
strategy: strategy
}, i, cancels = [], subobj;
for (i = 0; i < numberOfListenables; i++) {
_.throwIf(this.validateListening(listenables[i]));
}
for (i = 0; i < numberOfListenables; i++) {
// listen方法参数回调函数、上下文
cancels.push(listenables[i].listen(newListener(i, join), this));
}
reset(join);
subobj = {listenable: listenables};
subobj.stop = makeStopper(subobj, cancels, this);
this.subscriptions = (this.subscriptions || []).concat(subobj);
return subobj;
};
}
// ---- internal join functions ----
// 解绑事件
function makeStopper(subobj, cancels, context){
return function() {
var i, subs = context.subscriptions,
index = (subs ? subs.indexOf(subobj) : -1);
_.throwIf(index === -1, "Tried to remove join already gone from subscriptions list!");
for(i = 0; i < cancels.length; i++){
cancels[i]();
}
subs.splice(index, 1);
};
}
// 重置listenable的触发状况和传参
function reset(join) {
join.listenablesEmitted = new Array(join.numberOfListenables);
join.args = new Array(join.numberOfListenables);
}
// 同一个listenable多次触发,"last"取最后一次传参,"all"取所有传参,默认第一次传参
function newListener(i, join) {
return function() {
var callargs = slice.call(arguments);
if (join.listenablesEmitted[i]){
switch(join.strategy){
case "strict": throw new Error("Strict join failed because listener triggered twice.");
case "last": join.args[i] = callargs; break;
case "all": join.args[i].push(callargs);
}
} else {
join.listenablesEmitted[i] = true;
join.args[i] = (join.strategy === "all" ? [callargs] : callargs);
}
emitIfAllListenablesEmitted(join);
};
}
// 多个listenable事件触发后,执行callback回调函数,传参为传入多个listenable事件的参数对象
function emitIfAllListenablesEmitted(join) {
for (var i = 0; i < join.numberOfListenables; i++) {
if (!join.listenablesEmitted[i]) {
return;
}
}
join.callback.apply(join.listener, join.args);
reset(join);
}7.mixer.js
import * as _ from "./utils";
// 类似react的mixins,多个init、preEmit、shouldEmit或其他mixins中方法均将执行
export function mix(def) {
var composed = {
init: [],
preEmit: [],
shouldEmit: []
};
var updated = (function mixDef(mixin) {
var mixed = {};
if (mixin.mixins) {
mixin.mixins.forEach(function (subMixin) {
_.extend(mixed, mixDef(subMixin));
});
}
_.extend(mixed, mixin);
Object.keys(composed).forEach(function (composable) {
if (mixin.hasOwnProperty(composable)) {
composed[composable].push(mixin[composable]);
}
});
return mixed;
}(def));
if (composed.init.length > 1) {
updated.init = function () {
var args = arguments;
composed.init.forEach(function (init) {
init.apply(this, args);
}, this);
};
}
if (composed.preEmit.length > 1) {
updated.preEmit = function () {
return composed.preEmit.reduce(function (args, preEmit) {
var newValue = preEmit.apply(this, args);
return newValue === undefined ? args : [newValue];
}.bind(this), arguments);
};
}
if (composed.shouldEmit.length > 1) {
updated.shouldEmit = function () {
var args = arguments;
return !composed.shouldEmit.some(function (shouldEmit) {
return !shouldEmit.apply(this, args);
}, this);
};
}
Object.keys(composed).forEach(function (composable) {
if (composed[composable].length === 1) {
updated[composable] = composed[composable][0];
}
});
return updated;
}8.bindMethods.js
export function bindMethods(store, definition) {
for (var name in definition) {
if (Object.getOwnPropertyDescriptor && Object.defineProperty) {
var propertyDescriptor = Object.getOwnPropertyDescriptor(definition, name);
if (!propertyDescriptor.value || typeof propertyDescriptor.value !== "function" || !definition.hasOwnProperty(name)) {
continue;
}
store[name] = definition[name].bind(store);
} else {
var property = definition[name];
if (typeof property !== "function" || !definition.hasOwnProperty(name)) {
continue;
}
store[name] = property.bind(store);
}
}
return store;
}9.utils.js
export function capitalize(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
export function callbackName(string, prefix) {
prefix = prefix || "on";
return prefix + exports.capitalize(string);
}
/*
* isObject, extend, isFunction, isArguments are taken from underscore/lodash in
* order to remove the dependency
*/
export function isObject(obj) {
const type = typeof obj;
return type === "function" || type === "object" && !!obj;
}
export function extend(obj) {
if (!isObject(obj)) {
return obj;
}
var source, keys, prop;
for (var i = 1, length = arguments.length; i < length; i++) {
source = arguments[i];
keys = Object.keys(source);
for (var j = 0; j < keys.length; j++) {
prop = keys[j];
if (Object.getOwnPropertyDescriptor && Object.defineProperty) {
var propertyDescriptor = Object.getOwnPropertyDescriptor(source, prop);
Object.defineProperty(obj, prop, propertyDescriptor);
} else {
obj[prop] = source[prop];
}
}
}
return obj;
}
export function isFunction(value) {
return typeof value === "function";
}
exports.EventEmitter = require("eventemitter3");
export function nextTick(callback) {
setTimeout(callback, 0);
}
export function object(keys, vals){
var o = {}, i = 0;
for(;i < keys.length; i++){
o[keys[i]] = vals[i];
}
return o;
}
export function isArguments(value) {
return typeof value === "object" && ("callee" in value) && typeof value.length === "number";
}
export function throwIf(val, msg){
if (val){
throw Error(msg || val);
}
}10.Keep.js
// 记录及操作已添加的action、store
var use = false;
const createdStores = [];
const createdActions = [];
function useKeep(bool = true) {
use = bool;
}
function addStore(str) {
if (use) {
createdStores.push(str);
}
}
function addAction(act) {
if (use) {
createdActions.push(act);
}
}
function reset() {
while(createdStores.length) {
createdStores.pop();
}
while(createdActions.length) {
createdActions.pop();
}
}
export { useKeep, addStore, addAction, createdStores, createdActions, reset };11.actionMethods.js、storeMethods.js
export {}; 相关推荐
往后余生 2020-09-17
CXsilent 2020-09-16
webgm 2020-08-16
Lophole 2020-06-28
sqliang 2020-06-14
xcguoyu 2020-06-13
徐建岗网络管理 2020-06-11
前端开发Kingcean 2020-06-11
cbao 2020-06-10
yezitoo 2020-06-06
bigname 2020-06-04
前端开发Kingcean 2020-05-29
xiaofanguan 2020-05-29
ELEMENTS爱乐小超 2020-05-28
皖林 2020-05-11
wbczyh 2020-05-03
zuihaobushi 2020-04-30