1. 程式人生 > 實用技巧 >參考瀏覽器事件派發實現一個同步事件流

參考瀏覽器事件派發實現一個同步事件流

同步事件流:

串行同步執行,上一個事件處理函式的返回值作為引數傳遞給下一個事件處理函式

在函式中可以終止該階段後續函式的執行,也可以終止整個流程;

// 同步流程控制
        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 也不會被執行