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 {};

相关推荐