2016年12月16日 星期五

(js)series(鍊結方法版)

// 註冊錯誤處理函式
            $Series_.reject('b', error_fun);

            $Series_('b', b_1);
            $Series_('b', b_2); // 會拋出(reject)
            $Series_('b', b_3);



///////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *
 */
function $Series_(jobName, fn) {
    return $Series_._addSeries(jobName, fn);
};
/* ========================================================================== */
/**
 * ($Series_)的參數
 */
(function(self) {
    self.jobList = {};

    // 若沒有指定任務名,就用此預設的
    self.defaultJobName = 'fx';

    // 每個(job)本身要帶的資料
    self.defaultJobData = {
        'last': undefined, // 每個任務列最後一個工作節點
        'carryValue': undefined, // 紀錄每個工作節點的返回值
        'active': false, // 任務列是否在執行中
        'count': 0, // 等待中的數量
        'reject': undefined // 有(reject)過會放這
    };
})($Series_);
/* ========================================================================== */
/**
 * ($Series_)方法集
 */
(function(self) {
    /**
     * 把任務加入隊列
     *
     * 若隊列閒置,就執行
     */
    self._addSeries = function(jobName, fn) {
        debugger;

        if (typeof jobName == 'function') {
            jobName = self.defaultJobName;
            fn = jobName;
        }

        jobName = jobName || self.defaultJobData;
        /* ---------------------------------- */
        /**
         * 調出(job)
         */
        var job;

        if (typeof self.jobList[jobName] == 'undefined') {
            self.jobList[jobName] = Object.create(self.defaultJobData);
        }
        job = self.jobList[jobName];
        /* -------------------------------------------- */
        var Series = self.prototype.series;
        var now = new Series(jobName);
        /* -------------------------------------------- */
        /**
         * 處理節點間的關係
         */

        // 掛勾
        (job.last) && (job.last.next = now)

        job.last = now;
        ++job.count; // 通知(job)多加一個項目
        /* -------------------------------------------- */
        // 設定隊列要執行的事項
        now.setCallBack(fn);
        /* -------------------------------------------- */
        /**
         * 若沒在執行中
         *
         * 強制啟動
         */
        (!job.active) && (now.action());
        /* -------------------------------------------- */
        return now;

    };
    /* ====================================================================== */
    /**
     * 註冊錯誤事件(API)
     */
    self.reject = function(jobName, fn) {
        debugger;

        // 處理進來的參數
        if (arguments.length == 1) {

            if (typeof jobName == 'function') {
                fn = jobName;
                jobName = self.defaultJobName;
            } else if (jobName == null) {
                jobName = self.defaultJobName;
                fn = undefined;
            }
        }

        jobName = jobName || self.defaultJobName;
        /* ---------------------------------- */
        var jobData;

        if (typeof self.jobList[jobName] == 'undefined') {
            self.jobList[jobName] = Object.create(self.defaultJobData);
        }
        jobData = self.jobList[jobName];
        /* ---------------------------------- */
        jobData.reject = (typeof fn == 'function') ? fn : undefined;

    };
})($Series_);


/* ========================================================================== */
(function(_self) {
    // debugger;
    /**
     * 核心(序列)
     */
    function Series(jobName) {
        var self = this;

        // 下一個要執行的(series)
        this.next;
        this.fn = Series;
        /* ---------------------------------- */
        // 要執行的任務
        this.callBack;
        /* ---------------------------------- */
        /**
         * 參考所屬的工作隊列($Async_.jobList)
         *
         * 主要在設定(job.carryValue, active, last)
         */
        this.job;
        this.jobName = jobName || '';

        /* ================================================================== */
        this.__construct = function() {
            // debugger;

            // 取得所屬(job)
            this.job = _self.jobList[this.jobName];
        };
        /* ================================================================== */
        /**
         * call by window
         *
         * 要丟給(this.callBack)的參數
         * 任務結束時,要執行此,通知任務結束,開始下一步
         *
         */
        this._resolve = function(value) {
            // debugger;

            --self.job.count;

            if (arguments.length) {
                self.job.carryValue = value;
            }

            if (self.next) {
                // 若有下一步,執行下一步的(callBack)
                self.next.action();
            } else {
                // 沒有下一步,通知隊列結束

                self.job.last = undefined;
                self.job.active = false;
            }
        };
        /* ================================================================== */
        /**
         * call by window
         *
         * 隊列出錯,呼叫此
         * reset隊列,方便以後呼叫
         *
         */
        this._reject = function(data) {
            // debugger;

            /* ---------------------------------- */
            // 要傳送的資訊
            var carryValue = undefined;

            if (typeof self.job.carryValue == 'object') {
                carryValue = Object.create(self.job.carryValue);
            } else if (typeof self.job.carryValue != 'undefined') {
                carryValue = self.job.carryValue;
            }

            var _data = {
                'count': self.job.count,
                'data': carryValue,
                'error': data
            };
            /* ---------------------------------- */
            self.job.active = false;
            self.job.carryValue = undefined;
            self.job.last = undefined;
            self.job.count = 0;

            var reject_fun = self.job.reject;
            self.job.reject = undefined;
            /* ---------------------------------- */

            (typeof reject_fun == 'function') && reject_fun(_data);
        };
        /* ================================================================== */
        this.__construct();
    };
    ////////////////////////////////////////////////////////////////////////////
    (function() {
        /**
         * 主要任務(callBack)
         *
         * 執行(this.callBack)
         */
        this.action = function() {
            // debugger;
            var self = this;

            // 通知隊列在執行中
            this.job.active = true;

            /* -------------------------------------------- */
            if (typeof this.callBack != 'function') {
                return;
            }

            var info = {
                'active': this.job.active,
                'count': this.job.count,
                'data': this.job.carryValue,
                'reject': this.job.reject
            };

            // 執行任務(resolve, reject, carryValue, otherInfo)
            setTimeout(function() {
                self.callBack(self._resolve, self._reject, self.job.carryValue, info);
            }, 0);

        };
        /* ================================================================== */
    }).call(Series.prototype);
    /* ====================================================================== */
    (function() {
        this.__setGet = function() {};
        /* ================================================================== */
        /**
         * 設定要執行的(this.callBack)
         */
        this.setCallBack = function(fn) {
            if (typeof fn == 'function') {
                this.callBack = fn;
            }
        };
    }).call(Series.prototype);


    /* ====================================================================== */
    _self.prototype.series = Series;
})($Series_);