参考浏览器事件派发实现一个同步事件流

 

同步事件流: 

    串行同步执行,上一个事件处理函数的返回值作为参数传递给下一个事件处理函数

    在函数中可以终止该阶段后续函数的执行,也可以终止整个流程;

// 同步流程控制
        function SyncProcess(hooks) {
            // 所处阶段
            this.phase = null;
            // 最终停止冒泡的阶段
            this.bubPhase = null;
            // 阶段返回值
            this.returnValue = null;
            // 是否停止某同一类型事件
            this.cancel = false;
            // 是否停止所有事件
            this.cancelAll = false;
            // 流程节点
            this.hooks = hooks || [];
            // 节点的函数列表, 假定都是同步任务
            this.listeners = {}
        }

        SyncProcess.prototype.run = function (initData, initHook) {
            var returnValue = initData || null;
            var initHook = this.hooks.indexOf(initHook || null);
            var i = initHook === -1 ? 0 : initHook;

            for (; i < this.hooks.length; i++) {

                if (this.cancelAll) {
                    break;
                }
                var listeners = this.listeners[this.hooks[i]] || [];

                this.phase = this.hooks[i];

                for (var k = 0; k < listeners.length; k++) {

                    returnValue = listeners[k].call(null, returnValue, this);

                    if (this.cancelAll || (this.cancel && this.bubPhase === this.phase)) {
                        break
                    }
                }


            }

            this.returnValue = returnValue;
            return this
        }

        SyncProcess.prototype.registerHook = function (hook, index, callback) {
            if (typeof index === 'function') {
                callback = index;
                index = this.hooks.length
            }
            if (this.hooks.indexOf(hook) === -1) {
                this.hooks.splice(index, 0, hook)
            }

            if (hook in this.listeners) {
                this.listeners[hook].push(callback)
            } else {
                this.listeners[hook] = [callback]
            }
        }

        SyncProcess.prototype.removeHook = function (hook, callback) {
            var index = this.hooks.indexOf(hook)
            if (index === -1) {
                return
            } else {
                this.hooks.splice(index, 1);
                if (typeof callback === 'function') {
                    var fnIndex = this.listeners[hook].indexOf(callback);
                    if (fnIndex !== -1) {
                        this.listeners[hook].splice(fnIndex, 1)
                    }
                } else {
                    delete this.listeners[hook]
                }
            }
        }

        SyncProcess.prototype.stopPrograh = function () {
            this.bubPhase = this.phase
            this.cancel = true
        }

        SyncProcess.prototype.stopProcess = function () {
            this.cancelAll = true;
        }

        SyncProcess.prototype.continueProcess = function () {
            this.cancelAll = false;
            var curStep = this.hooks.indexOf(this.phase);
            if (curStep == this.hooks.length - 1) {
                return
            }

            this.run(this.returnValue, this.hooks[curStep + 1])
        }


        // 焖鸡
        var mj = {
            "准备": [
                function (v) { return v += '+土豆;' },
                function (v) { return v += '+洋葱;' },
                function (v) { return v += '+鸡肉;' }
            ],
            "切菜": [
                function (v) {
                    // if (v.indexOf('没肉啊') === -1) {
                    //     this.stopPrograh()
                    // }
                    return v += '+切菜 1;'
                },
                function (v, pross) { pross.stopProcess(); return v += '+切菜 2;'; }
            ],
            "烹饪": [
                function (v) { return v += '+大火爆炒 鸡肉;' },
                function (v) { return v += '+加配菜焖5分钟;' }
            ],
            "出锅": [
                function (v) { return v += '+加葱花 出锅;' }
            ]
        }
        var gx = Object.keys(mj);

        var cook = new SyncProcess(gx);
        gx.forEach(function (gx) {
            mj[gx].forEach(function (v) {
                cook.registerHook(gx, v)
            })
        });

        cook.registerHook('凉拌', 3, function (v) { return v + '搬一下:::' })
        cook.run();

        setTimeout(function () {
            cook.continueProcess();

            console.log(cook);
        }, 2000)
        console.log(cook);

 

同步流程只是理想情况, 大多数还是异步流程;从流程的角度来说, 我们写程序时也是有很多的过程,把过程进行分类,排列,可以让程序结构更为清晰易懂;

更多同步或异步流程的实现, 可以参考 tapable;附: https://www.cnblogs.com/tugenhua0707/p/11317557.html

 

注:

  浏览器的事件派发: 根据事件注册的阶段, 类型, 依照阶段和优先级顺序执行; 如果在某个函数中调用了 stopPropagation, 则停止父级同类型事件的传播; 如果调用了 stopImmediatePropagation,则

    停止父级同类型事件的传播, 并且停止当前对象上注册的同类型的其他事件的传播;

        举个例子:

            给 innerDom 的 mouseenter事件类型注册了事件 fn1, fn2, 给父级 outerDom 的mouseenter类型注册了事件 pfn1, pfn2;

            如果在 fn1 中调用了 stopPropagation, 则停止 mouseenter类型事件的冒泡, outerDom上为 mouseenter类型注册的事件 pfn1, pfn2 都不会被执行

            如果在 fn1 中调用了 stopImmediatePropagation, 则停止 mouseenter类型事件的冒泡, outerDom上为 mouseenter类型注册的事件 pfn1, pfn2 都不会被执行,并且innerDom 上为 mouseenter类型事件注册的其他函数 fn2 也不会被执行

posted @ 2020-12-14 16:57  芋头圆  阅读(94)  评论(0编辑  收藏  举报