
Hi我是前端人类学无论前端框架如何更迭防抖节流、发布订阅、Promise、路由、响应式这五个核心模块始终是支撑应用的基石。手写它们不仅能深入理解底层原理更能提升代码设计能力。本文将逐一实现并剖析其核心逻辑。文章目录一、防抖Debounce与节流Throttle1.1 防抖Debounce连续触发只执行最后一次1.2 节流Throttle固定时间间隔执行一次二、发布订阅Event Bus三、PromiseA 规范核心实现四、简易路由Hash 模式五、简易 Vue 响应式2.x 核心六、总结一、防抖Debounce与节流Throttle两者都是频率控制函数用于限制函数执行次数但适用场景截然不同。1.1 防抖Debounce连续触发只执行最后一次原理每次触发都重置定时器确保仅在停止触发后的等待时间结束后执行一次。functiondebounce(fn,delay300){lettimernull;returnfunction(...args){clearTimeout(timer);timersetTimeout((){fn.apply(this,args);},delay);};}适用场景输入框搜索联想、窗口 resize 计算。1.2 节流Throttle固定时间间隔执行一次原理通过时间戳或定时器控制在时间窗口内最多执行一次。functionthrottle(fn,interval300){letlastTime0;returnfunction(...args){constnowDate.now();if(now-lastTimeinterval){lastTimenow;fn.apply(this,args);}};}适用场景滚动加载、按钮高频点击防止重复提交。二、发布订阅Event Bus发布订阅模式是观察者模式的一种实现核心是事件中心订阅者on注册事件发布者emit触发事件同时支持移除off和一次性订阅once。classEventBus{constructor(){this.events{};}// 订阅on(name,callback){if(!this.events[name]){this.events[name][];}this.events[name].push(callback);}// 取消订阅off(name,callback){if(!this.events[name])return;if(!callback){deletethis.events[name];return;}this.events[name]this.events[name].filter(cbcb!callback);}// 触发emit(name,...args){if(!this.events[name])return;this.events[name].forEach(cbcb(...args));}// 一次性订阅once(name,callback){constwrapper(...args){callback(...args);this.off(name,wrapper);};this.on(name,wrapper);}}三、PromiseA 规范核心实现手写 Promise 的关键是理解状态流转pending → fulfilled / rejected和链式调用。核心骨架constPENDINGpending;constFULFILLEDfulfilled;constREJECTEDrejected;classMyPromise{constructor(executor){this.statePENDING;this.valueundefined;this.reasonundefined;this.onFulfilledCallbacks[];this.onRejectedCallbacks[];constresolve(value){if(this.statePENDING){this.stateFULFILLED;this.valuevalue;this.onFulfilledCallbacks.forEach(fnfn());}};constreject(reason){if(this.statePENDING){this.stateREJECTED;this.reasonreason;this.onRejectedCallbacks.forEach(fnfn());}};try{executor(resolve,reject);}catch(err){reject(err);}}then(onFulfilled,onRejected){onFulfilledtypeofonFulfilledfunction?onFulfilled:vv;onRejectedtypeofonRejectedfunction?onRejected:err{throwerr;};constpromise2newMyPromise((resolve,reject){if(this.stateFULFILLED){setTimeout((){try{constxonFulfilled(this.value);this.resolvePromise(promise2,x,resolve,reject);}catch(err){reject(err);}});}if(this.stateREJECTED){setTimeout((){try{constxonRejected(this.reason);this.resolvePromise(promise2,x,resolve,reject);}catch(err){reject(err);}});}if(this.statePENDING){this.onFulfilledCallbacks.push((){setTimeout((){try{constxonFulfilled(this.value);this.resolvePromise(promise2,x,resolve,reject);}catch(err){reject(err);}});});this.onRejectedCallbacks.push((){setTimeout((){try{constxonRejected(this.reason);this.resolvePromise(promise2,x,resolve,reject);}catch(err){reject(err);}});});}});returnpromise2;}// 核心解析处理 then 返回值的穿透和链式resolvePromise(promise2,x,resolve,reject){if(promise2x){returnreject(newTypeError(Chaining cycle detected));}if(x(typeofxobject||typeofxfunction)){letcalledfalse;try{constthenx.then;if(typeofthenfunction){then.call(x,y{if(called)return;calledtrue;this.resolvePromise(promise2,y,resolve,reject);},r{if(called)return;calledtrue;reject(r);});}else{resolve(x);}}catch(err){if(called)return;calledtrue;reject(err);}}else{resolve(x);}}// 静态方法staticresolve(value){returnnewMyPromise(resolveresolve(value));}staticreject(reason){returnnewMyPromise((_,reject)reject(reason));}// catch 是 then 的语法糖catch(onRejected){returnthis.then(null,onRejected);}}四、简易路由Hash 模式前端路由的核心是监听 URL 变化渲染对应组件。Hash 模式利用window.location.hash和hashchange事件实现。classRouter{constructor(){this.routes{};this.currentPath;// 监听 hash 变化window.addEventListener(hashchange,this.updateView.bind(this));// 页面加载时也要触发window.addEventListener(load,this.updateView.bind(this));}// 注册路由route(path,callback){this.routes[path]callback;}// 更新视图updateView(){constpathwindow.location.hash.slice(1)||/;this.currentPathpath;constcallbackthis.routes[path];if(callback){callback();}}// 跳转push(path){window.location.hashpath;}// 获取当前路径getCurrentPath(){returnthis.currentPath;}}// 使用示例constrouternewRouter();router.route(/,()console.log(首页));router.route(/about,()console.log(关于));router.push(/about);// 触发 about 路由五、简易 Vue 响应式2.x 核心Vue 2 的响应式核心是Object.defineProperty劫持数据结合发布订阅模式通知视图更新。核心三要素Observer、Dep、Watcher// 1. Dep依赖收集器发布订阅classDep{constructor(){this.subscribers[];}addSub(watcher){this.subscribers.push(watcher);}notify(){this.subscribers.forEach(watcherwatcher.update());}}// 2. Observer递归劫持所有属性functionobserve(obj){if(!obj||typeofobj!object)return;Object.keys(obj).forEach(keydefineReactive(obj,key,obj[key]));}functiondefineReactive(obj,key,val){constdepnewDep();// 深度劫持observe(val);Object.defineProperty(obj,key,{get(){// 依赖收集将当前 Watcher 添加到 depif(Dep.target){dep.addSub(Dep.target);}returnval;},set(newVal){if(newValval)return;valnewVal;observe(newVal);// 新值也需要劫持dep.notify();// 触发更新}});}// 3. Watcher观察者负责更新视图classWatcher{constructor(vm,key,callback){this.vmvm;this.keykey;this.callbackcallback;// 把当前 Watcher 挂到 Dep.target触发 getter 完成依赖收集Dep.targetthis;this.valuevm[key];// 读取触发 getterDep.targetnull;}update(){constnewValuethis.vm[this.key];if(newValue!this.value){this.valuenewValue;this.callback(newValue);}}}// 4. 简易 Vue 类classMiniVue{constructor(data){this._datadata;observe(data);}// 注册 Watcher$watch(key,callback){newWatcher(this,key,callback);}}// 使用示例constvmnewMiniVue({name:张三,age:18});vm.$watch(name,(newVal){console.log(姓名变了:,newVal);});vm._data.name李四;// 触发更新六、总结模块核心思想关键API/技术防抖延迟执行重置定时器setTimeoutclearTimeout节流时间窗口内只执行一次时间戳 / 定时器控制发布订阅事件中心管理回调on/emit/off/oncePromise状态机 链式调用resolve/reject/then路由(Hash)监听 hashchange 渲染组件window.location.hashVue响应式数据劫持 发布订阅Object.definePropertyDep/Watcher手写这些工具库本质上是理解设计模式观察者、发布订阅、代理和底层 APIdefineProperty、Proxy、Promise的过程。无论框架如何演变这些核心思想将始终伴随前端开发。