当前位置: 首页 > Web前端 > vue.js

从零开始实现Vue3的响应式库(一)

时间:2023-03-31 19:52:46 vue.js

Vue3鍜孷ue2鐨勫搷搴斿紡鏈夊緢澶х殑涓嶅悓銆傜敱浜嶸ue3浣跨敤Proxy鑰屼笉鏄痙efineProperty锛屽洜姝ue3鍦ㄥ搷搴斿紡鏁版嵁澶勭悊鏂归潰姣擵ue2鏈夋洿濂界殑琛ㄧ幇銆傛洿绠€娲侀珮鏁堢殑澶勭悊鏂瑰紡涔熷疄鐜颁簡寰堝鍦╒ue2涓婃棤娉曞疄鐜扮殑鍔熻兘銆傚彟澶栵紝Vue3鐨勫搷搴斿紡搴搑eactivity鏄竴涓崟鐙殑鍖咃紝鍙互鑴辩Vue杩愯锛屼篃灏辨槸璇存垜浠彲浠ュ湪鍏朵粬妗嗘灦涓繍琛屻€傚叾瀹濾ue3鐨勫搷搴斿紡搴撶殑瀹炵幇鍜屽競闈笂澶ч儴鍒嗗叾浠栧搷搴斿紡搴擄紙姣斿observer-util銆乵eteor绛夛級鐨勫疄鐜版槸宸笉澶氱殑锛岃€屼笖Vue涔熸槸鍙傝€冭繖浜涘簱瀹炵幇鐨勶紝鎵€浠ユ垜浠繕鏄緢鐔熸倝瀹冦€傚緢鏈夊繀瑕佸幓鐮旂┒涓€涓嬶紝姣曠珶鎴戜滑涓嶈兘钀藉悗馃槃锛屾墍浠ュ皬浼欎即浠紝涓€璧锋潵鐪嬬湅杩欎釜@vue/reactivity鏄浣曞疄鐜扮殑鍚с€傛湰鏂囨簮鐮佸凡缁忚创鍦ㄦ垜鐨刧it涓婁簡锛屽彲浠ュ幓鏌ョ湅锛歳eactivity鍦ㄩ槄璇绘湰鏂囦箣鍓嶏紝浣犲繀椤诲厛浜嗚В浠ヤ笅鐭ヨ瘑鐐筗eakMapSetReflectProxy涓婇潰涓嶆槑鐧界殑鍚屽鍙互鐩存帴鐐归摼鎺ユ煡鐪嬭缁嗘枃妗o紝鏂囦腑涓嶅啀璇﹁堪銆?-鍏堢湅涓€涓娇鐢╮eactivity鐨勪緥瀛?/鍒涘缓涓€涓搷搴斿紡瀵硅薄conststate=reactive({count:1})//鎵цeffecteffect(()=>{console.log(state.count)})state.count=2//褰揷ount鍙戠敓鍙樺寲鏃讹紝鎵цeffect涓殑鍑芥暟锛屾帶鍒跺彴杈撳嚭2銆傛湰渚嬮€氳繃reactive鍒涘缓涓€涓猺eactive瀵硅薄鐘舵€侊紝鐒跺悗璋冪敤effect鎵ц鍑芥暟銆傝繖涓嚱鏁板唴閮ㄨ闂簡state鐨勫睘鎬э紝鐒跺悗鎴戜滑鏀瑰彉杩欎釜state鐨勫睘鎬э紝杩欎釜鏃跺€欙紝鐢熸晥鐨勫嚱鏁板張浼氳鎵ц銆傞€氬父瀹炵幇杩欑鍝嶅簲寮忔暟鎹殑鏂瑰紡鏄畾涔変竴涓暟鎹负鍝嶅簲寮忥紙閫氬父閫氳繃defineProperty鎴朠roxy鏉ユ嫤鎴猤et銆乻et绛夋搷浣滐級骞跺畾涔変竴涓壇浣滅敤鍑芥暟锛坋ffect锛夈€傚綋sideeffectfunction鍐呴儴璁块棶reactivedata鏃朵細瑙﹀彂1涓殑getter锛岀劧鍚庡氨鍙互鍦ㄨ繖閲岄噰闆唀ffect浜嗐€傚綋淇敼鍝嶅簲寮忔暟鎹椂锛屼細瑙﹀彂1涓殑setter锛岀劧鍚庢墽琛?涓敹闆嗙殑鏁堟灉鍑芥暟銆傚叧浜巈ffect锛欵ffect鍦╒ue涓€氬父琚О涓簊ideeffectfunction锛屽洜涓烘绫诲嚱鏁伴€氬父浼氭墽琛屽叾浠栦换鍔★紝渚嬪缁勪欢娓叉煋鍜岃绠楀睘鎬с€傚湪鍏朵粬鐨勫簱涓紝瀹冨彲鑳借绉颁负瑙傚療鑰呭嚱鏁帮紙observe锛夋垨鍏朵粬锛屽彧瑕佷釜浜鸿兘澶熺悊瑙e畠鐨勬剰鎬濆嵆鍙€傜敱浜庢湰鏂囧垎鏋愮殑鏄疺ue3锛屾墍浠ョО涔嬩负鍓綔鐢ㄥ嚱鏁帮紙effect锛夈€傛牴鎹互涓婃€濊矾锛屾垜浠彲浠ュ厛寮€濮嬪疄鐜皉eactive銆傛垜浠渶瑕佷竴涓弽搴斿嚱鏁版潵浣挎垜浠殑鏁版嵁鍝嶅簲銆?/reactive.tsimport{baseHandlers}from'./handlers'import{isObject}from'./utils'typeTarget=objectconstproxyMap=newWeakMap()瀵煎嚭鍑芥暟reactive(target:T):T{returncreateReactiveObject(target)}functioncreateReactiveObject(target:Target){//鍙粰瀵硅薄娣诲姞reactiveif(!isObject(target)){returntarget}//Reactive鏁版嵁涓嶈兘閲嶅瀹氫箟if(proxyMap.has(target)){returnproxyMap.get(target)}//閫氳繃Proxy鎷︽埅瀵规暟鎹殑鎿嶄綔constproxy=newProxy(target,baseHandlers)//鍚慞roxyMap涓坊鍔犳暟鎹畃roxyMap.set(target,proxy)returnproxy}杩欓噷涓昏閽堝鏁版嵁绠€鍗曞垽鏂竴涓嬶紝鍏抽敭鏄痗onstproxy=newProxy(target,baseHandlers)涓€氳繃Proxy澶勭悊鏁版嵁锛屽叾涓璪aseHandlers鏄嫤鎴猤et锛宻et绛夋暟鎹紝鎴戜滑鍏堝疄鐜癰aseHandlersget闆嗗悎渚濊禆瀹炵幇鎷︽埅get鎿嶄綔锛岃繖鏍峰湪璁块棶鏁版嵁鐨勬煇涓猭ey鏃讹紝鍑芥暟锛堜綔鐢級鍙互鏀堕泦鍜屽瓨鍌ㄨ闂瀵嗛挜鐨勪俊鎭€?/handlers.tsimport{track}from'./effect'import{reactive,Target}from'./reactive'import{isObject}from'./utils'exportconstbaseHandlers:ProxyHandler={get(target:Target,key:string|symbol,receiver:object){//鏀堕泦鏁堟灉鍑芥暟track(target,key)//鑾峰彇杩斿洖鍊糲onstres=Reflect.get(target,key,receiver)//濡傛灉鏄竴涓猳bject锛岄渶瑕侀噸鏂版墽琛宺eactive骞秗eturnif(isObject(res)){returnreactive(res)}returnres}}杩欓噷鎴戜滑鎷︽埅get鎿嶄綔锛岄€氳繃track鏀堕泦渚濊禆銆倀rack鍑芥暟鎵€鍋氱殑灏辨槸鏀堕泦褰撳墠鐨別ffect鍑芥暟锛屾墽琛屽畬track鍚庯紝鑾峰彇target鐨刱ey鍊煎苟杩斿洖銆傛敞鎰忚繖閲屾槸鍒ゆ柇res鏄惁鏄竴涓璞°€傚鏋滃畠鏄竴涓璞★紝瀹冨簲璇ヨ繑鍥瀝eactive(res)鍥犱负瀹冭涓哄彲鑳芥湁澶氫釜宓屽瀵硅薄銆?鑰孭roxy鍙兘淇敼涓哄綋鍓嶅璞★紝涓嶈兘淇敼涓哄瓙瀵硅薄锛屾墍浠ヨ繖閲岄渶瑕佸鐞嗕竴涓嬨€傛帴涓嬫潵闇€瑕佸疄鐜皌rack鍑芥暟//effect.ts//瀛樺偍渚濊禆绫诲瀷Deps=Set//閫氳繃key鑾峰彇渚濊禆锛宬ey=>DepstypeDepsMap=Map//閫氳繃target鑾峰彇DepsMap,target=>DepsMapconsttargetMap=newWeakMap()//褰撳墠姝e湪鎵ц鐨別ffectletactiveEffect:ReactiveEffect|undefined//鏀堕泦渚濊禆瀵煎嚭鍑芥暟track(target:object,key:unknown){if(!activeEffect){return}//鑾峰彇杩欎釜target瀵瑰簲鐨刣epsMapletdepsMap=targetMap.get(target)//濡傛灉depsMap涓嶅瓨鍦ㄥ垯鍒涘缓涓€涓柊鐨刬f(!depsMap){targetMap.set(target,(depsMap=newMap()))}//鏈変簡depsMap涔嬪悗锛屾牴鎹甼ey鑾峰彇key瀵瑰簲鐨刣epsletdeps=depsMap.get(key)//涔熶竴鏍蜂笉瀛樺湪鍙渶鍒涘缓涓€涓柊鐨刬f(!deps){depsMap.set(key,(deps=newSet()))}//娣诲姞activeEffect鍒癲epsif(!deps.has(activeEffect)){deps.add(activeEffect)}}娉ㄦ剰杩欓噷鏄袱寮犲浘涓€缁勶紝targetMap=>depsMap=>deps锛岃繖鏍锋垜浠氨鍙互閫氳繃target鍜宬ey鍑嗙‘鑾峰彇key瀵瑰簲鐨刣eps(effect)锛屾妸褰撳墠鎵ц鐨別ffect(activeEffect)淇濆瓨锛岃繖鏍峰綋浣犱慨鏀箃arget[key]鏃讹紝灏卞彲浠ラ€氳繃target鍜宬ey鑾峰彇鍒颁箣鍓嶆敹闆嗙殑鎵€鏈変緷璧栵紝骞舵墽琛屻€傝繖閲屾湁涓棶棰橈紝杩欎釜activeEffect鏄粠鍝噷鏉ョ殑銆俫etis濡備綍鐭ラ亾褰撳墠姝e湪鎵ц鐨勬晥鏋滐紵杩欎釜闂鍙互鍏堟悂缃竴浼氾紝浠ュ悗鍐嶈璁猴紝鍏堝疄鐜拌繖涓猻et瀹炴柦set//handlers.tsexportconstbaseHandlers:ProxyHandler={get(){//...},set(target:Target,key:string|symbol,value:any,receiver:object){//setvalueconstresult=Reflect.set(target,key,value,receiver)//notifyupdatetrigger(target,key,value)returnresult}}鎴戜滑鍦ㄥ垰鎵嶇殑baseHandlers涓嬫坊鍔犱簡涓€涓猻et锛岃繖涓猻et涓昏鏄祴鍊肩劧鍚庨€氱煡鏇存柊锛岄€氱煡鏇存柊鏄€氳繃瑙﹀彂鍣ㄨ繘琛岀殑锛屾垜浠渶瑕佸湪get涓幏鍙栨敹闆嗗埌鐨勪緷璧栵紝骞舵墽琛岋紝涓嬮潰鏄疄鐜拌Е鍙戝櫒鍑芥暟//effect.ts//閫氱煡鏇存柊瀵煎嚭鍑芥暟trigger(target:object,key:any,newValue?:any){//鑾峰彇瀵硅薄鐨刣epsMapconstdepsMap=targetMap.get(target)//濡傛灉鑾峰彇涓嶅埌锛岃鏄巊etter娌℃湁琚Е鍙?!depsMap){return}//鐒跺悗鏍规嵁key寰楀埌deps锛屼篃灏辨槸涔嬪墠瀛樺偍鐨別ffectfunctionconsteffects=depsMap.get(key)//鎵ц鎵€鏈塭ffectfunctionsif(effects){effects.forEach((effect)=>{effect()})}}杩欎釜trigger灏辨槸鍘昏幏鍙栦箣鍓嶉噰闆嗗埌鐨別ffect骞舵墽琛屻€傚叾瀹為櫎浜唃et鍜宻et涔嬪锛岃繕鏈変竴涓父鐢ㄧ殑鎿嶄綔锛屽氨鏄垹闄ゅ睘鎬с€傜幇鍦ㄦ垜浠棤娉曟嫤鎴垹闄ゆ搷浣溿€傝鎴戜滑瀹炴柦deletePropertyexportconstbaseHandlers锛歅roxyHandler={get(){//...},set(){//...},deleteProperty(target:Target,key:string|symbol){//鍒ゆ柇瑕佸垹闄ょ殑key鏄惁瀛樺湪consthadKey=hasOwn(target,key)//鎵ц鍒犻櫎operationconstresult=Reflect.deleteProperty(target,key)//鍙湁褰搆ey瀛樺湪涓斿垹闄ゆ垚鍔熸椂鎵嶉€氱煡鏇存柊if(hadKey&&result){trigger(target,key,undefined)}returnresult}}Wearein鍒氭墠鐨刡aseHandlers娣诲姞浜嗕竴涓猟eleteProperty锛屽彲浠ユ嫤鎴暟鎹殑鍒犻櫎銆傝繖閲岄渶瑕佸垽鏂鍒犻櫎鐨刱ey鏄惁瀛樺湪锛屽洜涓虹敤鎴峰彲鑳藉垹闄や簡涓€涓笉瀛樺湪鐨刱ey锛岀劧鍚庡啀鍒犻櫎銆傛垜浠彧瀛樺湪瀵嗛挜骞跺皢鍏跺垹闄ゃ€傛垚鍔熸椂閫氱煡鏇存柊锛屽洜涓哄鏋渒ey涓嶅瓨鍦紝鍒犻櫎娌℃湁鎰忎箟锛屼篃涓嶉渶瑕佹洿鏂帮紝濡傛灉鍒犻櫎鎿嶄綔澶辫触锛屼篃涓嶉渶瑕佹洿鏂帮紝鏈€鍚庣洿鎺ヨЕ鍙憈rigger灏卞彲浠ヤ簡锛岃繖閲岃娉ㄦ剰绗笁涓弬鏁皏alue鏄痷ndefined銆傜幇鍦ㄦ垜浠凡缁忓疄鐜颁簡get銆乻et銆乨eleteProperty杩欎笁涓搷浣滅殑鎷︽埅銆傝繕璁板緱track鍑芥暟涓殑activeEffect鍚楋紵鏈変釜闂锛岃繖涓猘ctiveEffect鏄€庝箞鏉ョ殑锛燂紵锛屽湪绗竴涓緥瀛愪腑锛屾垜浠渶瑕侀€氳繃effect鏉ユ墽琛屽嚱鏁帮紝杩欓噷璁剧疆浜嗚繖涓猘ctiveEffect锛屼笅闈㈡垜浠潵瀹炵幇杩欎釜effect鍑芥暟銆?/effect.tstypeReactiveEffect=()=>T//瀛樺偍鏁堟灉鐨勮皟鐢ㄥ爢鏍坈onsteffectStack:ReactiveEffect[]=[]exportfunctioneffect(fn:()=>T):ReactiveEffect{//鍒涘缓鏁堟灉鍑芥暟consteffect=createReactiveEffect(fn)returneffect}functioncreateReactiveEffect(fn:()=>T):ReactiveEffect{consteffect=functionreactiveEffect(){//褰撳綋鍓峞ffectStack璋冪敤鏍堜腑涓嶅瓨鍦╡ffect鏃舵墽琛岋紝閬垮厤姝诲惊鐜痠f(!effectStack.includes(effect)){try{//灏嗗綋鍓峞ffectStack娣诲姞鍒癳ffectStackeffectStack.push(effect)//璁剧疆褰撳墠鏁堟灉锛屼互渚縋roxy涓殑getter鍙互璁块棶鍒?//灏哸ctiveEffect鎭㈠涓篴ctiveEffect=effectStack[effectStack.length-1]}}}asReactiveEffectreturneffect}杩欓噷涓昏鏄垱寤轰竴涓晥鏋渇un閫氳繃createReactiveEffect瀹炵幇鐨刢tion锛宖n鏄皟鐢╡ffect鏃朵紶鍏ョ殑鍑芥暟锛屾墽琛岃繖涓猣n鐨勬椂鍊欎箣鍓嶏紝閫氳繃effectStack.push(effect)鎶婅繖涓猠ffect鍘嬪叆effectStack鏍堜腑锛屽洜涓篹ffect鍙兘鏈夊祵濂楄皟鐢紝淇濆瓨鍚庡彲浠ュ緱鍒颁竴涓畬鏁寸殑effect璋冪敤鏍堬紝鍙互閫氳繃涓婇潰鐨別ffectStack.includes(effect)纭畾鏄惁鏈夊惊鐜皟鐢紝鐒跺悗鐢╝ctiveEffect=effect璁剧疆activeEffect锛岃缃畬涔嬪悗鍐嶆墽琛宖n锛屽洜涓鸿繖涓猘ctiveEffect鏄叏灞€鍞竴鐨勶紝鎵€浠ユ垜浠湪鎵цfn鐨勬椂鍊欙紝濡傛灉鍐呴儴璁块棶鐨勬槸鍝嶅簲寮忔暟鎹紝灏卞彲浠ユ嬁鍒癵etter涓殑activeEffect锛岀劧鍚庢敹闆嗗畠銆傜幇鍦ㄥ熀鏈畬鎴愪簡銆傜幇鍦ㄤ緥瀛愪腑鐨勬晥鏋滃彲浠ラ€氳繃鎴戜滑鍐欑殑reactivity搴撴潵瀹炵幇锛屼絾鏄繕鏄湁涓€浜涜竟鐣屾潯浠堕渶瑕佽€冭檻銆備笅涓€绡囨枃绔犲皢娣诲姞涓€浜涘父瑙佺殑杈圭紭妗堜緥澶勭悊銆?/p>