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

Vue2源码-响应式原理

时间:2023-04-01 12:44:44 vue.js

鍝嶅簲寮忓師鐞嗘杩板ぇ鑷存祦绋嬨€傞鍏堝疄渚嬪寲Vue锛岃皟鐢╛init鏂规硶锛屽垵濮嬪寲鏁版嵁銆佹柟娉曘€亀atch銆乸rops銆佺敓鍛藉懆鏈熺瓑锛岄€氳繃璋冪敤observer鍑芥暟observer鐢熸垚浠g悊瀵硅薄锛屽璞′笂浼氭湁涓€涓猒_ob__灞炴€у氨鏄疄渚媜bserver鐨勶紝琛ㄧず瀵硅薄琚唬鐞嗭紝閫氳繃defineReactive$$1鏂规硶浠g悊琚唬鐞嗗璞′腑鐨勬瘡涓睘鎬э紙濡傛灉灞炴€у€兼槸瀵硅薄鎴栬€呮暟缁勶紝閫掑綊鍚戜笅鎵ц锛夛紝瀵硅薄浠g悊鍔熻兘鐨勫疄鐜版柟寮忎负浣跨敤Object.defineProperty鐨勫師鐢焌pi銆侽bject.defineProperty鍒嗗埆瀹氫箟浜唃et鍜宻et鏂规硶銆俫et鏂规硶鍦ㄥ紩鐢ㄥ璞″睘鎬ф椂瑙﹀彂渚濊禆鏀堕泦锛宻et鏂规硶鐢ㄤ簬淇敼灞炴€у苟鎵цupdate鏂规硶銆?mount鏂规硶涓細瑙f瀽妯℃澘锛屽紩鐢ㄧ殑瀵硅薄灞炴€т細瑙﹀彂渚濊禆鏀堕泦鐢熸垚vNode锛岀劧鍚庢覆鏌撶湡姝g殑瑙嗗浘銆備箣鍚庯紝褰撳睘鎬ф洿鏂版椂锛屼細瑙﹀彂set鏂规硶杩涜鏇存柊銆備粠婧愮爜瑙掑害鍒嗘瀽鍒濆鍖栧疄渚媫this._init(閫夐」);}_init鍒濆鍖朧ue瀹炰緥锛宊init瀹氫箟鍦ㄥ師鍨嬮摼涓婏紝鏌ョ湅Vue.prototype._init涓殑鍐呭锛屽叾涓璱nitLifecycle鍒ゆ柇缁勪欢鐨勫眰绾э紝鐖剁粍浠讹紝鏍圭粍浠讹紝瀹氫箟灞炴€т繚瀛樺瓙缁勪欢锛寃ather瀵硅薄锛岃褰昄ifecycle鎵ц鐘舵€佸睘鎬х瓑锛沬nitEvents鍋氫竴浜涚埗绾х洃鎺у姛鑳界浉鍏崇殑鎿嶄綔锛沬nitRender鍒濆鍖栦竴浜涗笌铏氭嫙DOM鐩稿叧鐨勫睘鎬у拰鏂规硶銆俰njectinitInjections灞炴€ф敞鍏ワ紝閰嶅悎鏂囨。锛岃繖閲屽拰props灞炴€у緢鍍忥紝inject鏍煎紡搴旇鏄瓧绗︿覆鏁扮粍鎴栬€呭璞★紝鍏蜂綋鍦╮esolveInject鍑芥暟涓紝濡傛灉鏄暟缁勶紝姣忎竴椤瑰搴旂殑灞炴€у湪鎻愪緵;濡傛灉鏄璞★紝鍒欏垽鏂璞$殑灞炴€у€肩被鍨嬨€傚鏋滄槸瀵硅薄锛屽垯闇€瑕佸寘鍚竴涓粯璁ゅ睘鎬э紝杩斿洖榛樿灞炴€х殑鍊笺€傚惁鍒欙紝璇ュ€煎搴斾簬provide涓殑灞炴€с€傚悓鏃朵細缁х画鏌ヨ娉ㄥ叆鐨勫睘鎬э紝鐩村埌鎵惧埌鍖呭惈璇ュ睘鎬х殑provide鎴栬€呮壘涓嶅埌鏍圭粍浠躲€傛渶缁堢敓鎴愮殑瀵硅薄浼氳娉ㄥ叆鍒板綋鍓嶇殑Vue瀹炰緥涓€傛敞鍏ヨ繃绋嬩腑浼氫娇鐢╰oggleObserving淇敼shouldObserve鐘舵€佷负false锛屾敞鍏ョ殑瀵硅薄涓嶄細浣滀负浠g悊閫掑綊鍚戜笅銆俰nitState鍒濆鍖杁ata銆乸rops銆乵ethods銆乧omputed鍜寃atch绛夊睘鎬с€傝繖涔熸槸Vue瀹炵幇鍝嶅簲鎬у師鍒欑殑鍦版柟銆傚厛鏀剧潃璇达紝鍏堜粙缁嶄竴涓嬫敞鍏ャ€俰nitProvide鎻愪緵浜嗕负鍓嶉潰鐨刬nitInjections鎻愪緵鐨勬敞鍏ユ柟娉曘€傝繖閲屾煡鐪嬩竴涓嬭繖鍑犱釜鍑芥暟鐨勬墽琛岄『搴廼nitInjections=>initState=>initProvide鍏堟妸initState鏀惧湪initInjections鍚庨潰锛岃繖鏄负浜嗛槻姝ata涓殑灞炴€ц瑕嗙洊锛屾渶鍚庢墽琛宨nitProvide锛屽洜涓哄畠鎻愪緵鏁版嵁锛屾渶澶栧眰娌℃湁娉ㄥ叆鏄繀椤荤殑銆傚悗缁瓙瀛欑粍浠朵腑鐨刬nject鍙互閫氳繃鏌ユ壘绁栧厛缁勪欢鏉ヨ闂渶澶栧眰鐨凱rovider銆傚搷搴斿紡瀹炵幇鍥炲ご鐪媔nitState鏂规硶锛屽叾涓渶閲嶈鐨勬槸鍏呭綋鏁版嵁鐨勫璞′唬鐞嗐€傛墽琛宱bserve鏂规硶锛屼互瑙傚療鑰呬负鏋勯€犲嚱鏁帮紝浠ユ暟鎹负鍙傛暟鐢熸垚瑙傚療鑰呭璞★紝value灞炴€х敤浜庝繚瀛樻暟鎹紝浠g悊瀵硅薄浣跨敤__ob__灞炴€т繚瀛樿瀵熻€呭疄渚嬶紝dep灞炴€х敓鎴愬璞$殑璁㈤槄鑰咃紝鐒跺悗璋冪敤鍘熷瀷涓婄殑鏂规硶walk锛屼緷娆′娇鐢╠efineReactive$$1瀵规暟鎹璞′腑鐨勬瘡涓睘鎬ц繘琛屼唬鐞嗘搷浣溿€俤efineReactive$$1defineReactive$$1棣栧厛鐢熸垚涓€涓狣ep璁㈤槄鑰咃紝鐒跺悗鍒ゆ柇灞炴€ф槸鍚﹀彲閰嶇疆锛岀劧鍚庡垽鏂睘鎬у€兼槸瀵硅薄杩樻槸鏁扮粍锛岀劧鍚庤繘涓€姝ユ瀯閫犺瀵熻€呭璞★紝鍚庨潰鏄疧bject.defineProperty鏂规硶锛岃繖涔熻Vue鎴愪负浜嗕竴涓彲浠ュ疄鐜板搷搴斿紡鍘熺悊鐨凙PI銆侽bject.defineProperty鏈€鍒濇槸涓轰簡瀹氫箟灞炴€т慨楗扮锛屽寘鎷睘鎬х殑鍙慨鏀规€с€佸彲閰嶇疆鎬у拰鏋氫妇鎬с€傚悓鏃惰繕鍙互瀹氫箟get鍜宻et鏂规硶锛屽垎鍒湪灞炴€т慨鏀规椂璇诲彇鍒癊xecute锛屾墍浠ョ敤杩欎袱涓柟娉曞仛涓€浜涙墿灞曪紝get鏂规硶浼氬湪鑾峰彇灞炴€у€肩殑鍩虹涓婃敹闆嗕緷璧栨墽琛岋紝set鏂规硶浼氶€氱煡鎵€鏈変緷璧栬灞炴€у搴攄ep鐨剋atcher瑙傚療鑰呮洿鏂拌鍥俱€傜畝鍗曚粙缁嶅畬defineReactive$$1锛屽啀浠旂粏鐪嬩竴涓嬭繖涓嚱鏁颁腑涓や釜鍏抽敭鐨勪笢瑗匡細Dep锛學atcherDep璁㈤槄鑰呮瀯閫犲嚱鏁帮紝姣忎釜灞炴€ч兘浼氭柊寤轰竴涓猟ep璁㈤槄鑰咃紝dep涓湁涓€涓猻ubs灞炴€э紝鍏朵腑涓€涓槸dep.target鍏ㄥ眬鍙橀噺浼氭寚鍚戝綋鍓嶇殑watcher瑙傚療鑰咃紝鐒跺悗鍦ㄨ鍥句腑寮曠敤杩欎釜灞炴€ф椂锛屼細灏嗗綋鍓峸atcher瑙傚療鑰呭璞℃坊鍔犲埌璇ュ睘鎬х殑dep璁㈤槄鑰呬腑鐨剆ubs涓€傚綋灞炴€ф洿鏂版椂锛屼細璋冪敤瀵瑰簲dep涓殑notify鏂规硶锛岄€氱煡subs涓殑鎵€鏈墂atcher鎵цupdate鏇存柊瑙嗗浘銆俉atcher瑙傚療鑰呮瀯閫犲嚱鏁帮紝涓婇潰浠嬬粛鐨勯儴鍒嗭紝姣忎釜Vue瀹炰緥涓兘浼氭湁涓€涓猒watcher灞炴€у搴斾竴涓獁atcher瑙傚療鑰咃紝涓嬮潰鐨勪緷璧栨敹闆嗚繃绋嬩細璇︾粏浠嬬粛Watcher銆傝繖鏃跺€欏簲璇ヤ細鏈夊浘鐗囨弿杩帮細瀵硅薄浠g悊銆丏ep銆乄atcher銆佷緷璧栨敹闆嗐€佽櫄鎷烡OM銆佹覆鏌撹鍥剧瓑銆備緷璧栨敹闆嗘帴涓嬫潵鎴戜滑浠嬬粛渚濊禆鏀堕泦鏄粈涔堟椂鍊欏彂鐢熺殑銆傚洖杩囧ご鏉ョ湅锛屽湪鏁版嵁鐨勬敞鍏ュ拰鍒濆鍖栫瓑涔嬪悗锛屽厛鎵ц鍒涘缓鐨勫洖璋冨嚱鏁帮紝鐒跺悗鎵ц$mount鎸傝浇缁勪欢銆傝繖閲屾湁鎰忔€濈殑鏄紝浣滆€呭Vue杩涜浜嗕袱娆″畾涔夈€俻rototype.$mount锛屼竴寮€濮嬫垜涔熻寰楀鎬紝褰撶劧鍚庨潰鐨勫畾涔変細瑕嗙洊鍓嶉潰鐨勶紝灏辩敤涓€琛屼唬鐮乿armount=Vue.prototype.$mount;淇濆瓨瑕嗙洊鍓嶇殑绗竴涓柟娉曪紝鐒跺悗鏌ョ湅鏂扮殑$mount鏂规硶锛屼富瑕佹槸瑙f瀽缂栬瘧妯℃澘绛夋搷浣滐紝鏈€鍚庣敓鎴愪竴涓猺ender鍑芥暟锛岀劧鍚庢墽琛屼箣鍓嶄繚瀛樼殑鏃х殑$mount鏂规硶锛屼娇鐢╩ountComponent.鍙互鐪嬪埌鍦ㄥ紑濮嬩箣鍓嶄細鍋氫竴浜涙鏌ュ垽鏂璻ender鏄惁瀛樺湪锛屽鏋滀笉瀛樺湪锛屽氨璧嬬粰涓€涓粯璁ゆ柟娉曪紙鍒涘缓涓€涓彧鍖呭惈鏂囨湰鐨勮櫄鎷烡OM锛夛紝骞舵姏鍑鸿鍛娿€傜劧鍚庢墽琛宐eforeMount鐢熷懡鍛ㄦ湡鍑芥暟锛岀劧鍚庡畾涔変竴涓猽pdateComponent鏂规硶锛岀敤浜庤Е鍙戜緷璧栨敹闆嗭紝鏍规嵁瀵硅薄灞炴€х殑寮曠敤鐢熸垚vNode銆傜湅浜嗕箣鍚庯紝棣栧厛鏂板缓涓€涓猈atcher瀵硅薄锛寀pdateComponent鏂规硶浼氫綔涓虹浜屼釜鍙傛暟浼犲叆銆傛帴涓嬫潵鐪嬬湅Watcher鏄浣曞畾涔夌殑銆倂arWatcher=functionWatcher(vm,expOrFn,cb,options,isRenderWatcher){this.vm=vm;濡傛灉锛坕sRenderWatcher锛墈vm._watcher=this;}vm._watchers.push(杩欎釜);//閫夐」if(options){this.deep=!!options.deep;this.user=!!options.user;this.lazy=!!options.lazy;this.sync=!!options.sync;this.before=options.before;}else{this.deep=this.user=this.lazy=this.sync=false;}杩欎釜.cb=cb;this.id=++uid$2;//鐢ㄤ簬鎵瑰鐞嗙殑uidthis.active=true;this.dirty=this.lazy;//瀵逛簬鎳掓儼鐨勮瀵熻€卼his.deps=[];杩欎釜.newDeps=[];this.depIds=new_Set();this.newDepIds=new_Set();this.expression=expOrFn.toString();//涓篻etter瑙f瀽琛ㄨ揪寮廼f(typeofexpOrFn==='function'){this.getter=expOrFn;}else{this.getter=parsePath(expOrFn);濡傛灉锛堬紒this.getter锛墈this.getter=noop;鎴樹簤n("Failedwatchingpath:\""+expOrFn+"\""+'Watcher鍙帴鍙楃畝鍗曠殑鐐瑰垎闅旇矾寰勩€?+'瑕佸畬鍏ㄦ帶鍒讹紝璇锋敼鐢ㄥ嚱鏁般€?,vm);}}this.value=this.lazy锛熸湭瀹氫箟锛歵his.get()锛泒;Watcher.prototype.get=functionget(){pushTarget(this);鍙橀噺鍊硷紱varvm=this.vm;try{value=this.getter.call(vm,vm);}catch(e){if(this.user){handleError(e,vm,("getterforwatcher\""+(this.expression)+"\""));}else{throwe}}finally{//鈥滆Е鎽糕€濇瘡涓睘鎬э紝浠ヤ究瀹冧滑閮借璺熻釜涓?/娣卞害瑙傚療鐨勪緷璧栭」if(this.deep){traverse(value);}寮瑰嚭鐩爣锛堬級锛涜繖涓?cleanupDeps();}杩斿洖鍊紏;鍒濆鍖栦竴绯诲垪灞炴€у拰鏂规硶銆傛瀯閫犺瀵熻€呭璞℃椂锛屽皢璋冪敤鍘熷瀷涓婄殑get鏂规硶銆傝鏂规硶浼氬厛璋冪敤pushTarget灏咲ep.target鍙樹负褰撳墠watcher锛岀劧鍚庤皟鐢ㄥ璞′腑鐨刧etter鏂规硶銆傚綋getter瀵瑰簲鍓嶉潰鐨剈pdateComponent鏂规硶鏃讹紝updateComponent鐪熸琚墽琛屼簡锛屼細璋冪敤Vue瀹炰緥涓婄殑_render鏂规硶Vue.prototype._render=function(){varvm=this;varref=vm.$閫夐」锛泇arrender=ref.render;var_parentvNode=鍙傝€冦€俖parentvNode锛?/...鐪佺暐鍒嗚...varvNode;//...鐪佺暐鍒嗚...vNode.parent=_parentvNode;returnvNode缁忚繃涓€绯诲垪鎿嶄綔锛屽畬鎴愪緷璧栨敹闆嗭紝杩斿洖瀵瑰簲鐨剉Node锛屽嵆铏氭嫙DOM銆倂Node鏈変竴涓噸瑕佺殑灞炴€х埗鑺傜偣銆傚鏋滀负绌猴紝鍒欒〃绀鸿鑺傜偣涓烘牴鑺傜偣銆傝櫄鎷烡OM涔嬪悗锛岃繕瑕佺粡杩嘷update銆乢_patch__绛変富瑕佹槸diff绠楁硶鐨勯儴鍒嗐€傞櫎绗竴娆Node涓嶅瓨鍦ㄥ锛屾洿鏂版椂浜х敓鏂扮殑vNode鍚庯紝涓嶄細鏁翠綋鏇存柊锛岃€屾槸閫氳繃diff澶勭悊鐢熸垚鏈€灏忔洿鏂板崟鍏冿紝浠ユ彁楂樻€ц兘銆倁pdateComponent灏嗗湪鎵ц缁撴潫鍓嶈璋冪敤銆俻opTarget鏂规硶灏咲ep.target杩斿洖鍒颁互鍓嶇殑鍊笺€侱ep.target=null;鍙樼targetStack=[];鍑芥暟pushTarget锛堢洰鏍囷級{targetStack.push锛堢洰鏍囷級锛汥ep.target=鐩爣锛泒functionpopTarget(){targetStack.pop();Dep.target=targetStack[targetStack.length-1];}涓轰粈涔堣鐢ㄤ竴涓暟缁則argetStack鏉ヤ繚瀛榳atcher锛岃繖涓窡鐖跺瓙缁勪欢鎸傝浇鏇存柊瑙勫垯鏈夊叧锛宲arentbeforeCreate=>parentcreated=>parentbeforeMount=>childbeforeCreate=>childcreated=>childbeforeMount=>childmounted=>鐖跺畨瑁呫€傝繖灏辨槸鐖跺瓙缁勪欢鐢熷懡鍛ㄦ湡鍦ㄦ寕杞介樁娈电殑鎵ц椤哄簭銆傚洜涓哄瓙缁勪欢鐨勪緷璧栨敹闆嗗彂鐢熷湪beforeMount涔嬪悗鍜宮ounted涔嬪墠锛屽鏋滅埗缁勪欢涓湁瀛愮粍浠讹紝瀛愮粍浠朵細鏋勯€犱竴涓柊鐨剋atcher瀵硅薄銆傛鏃剁埗缁勪欢渚濊禆鏀堕泦杩樻病鏈夌粨鏉燂紝pushTarget鎿嶄綔浼氬皢鐖剁粍浠剁殑watcher鎺ㄥ叆targetStack涓紝鎸傝捣锛屽瓙缁勪欢鐢熸垚vNode鍚庯紝popTarget鍚庯紝Dep.target杩斿洖鍒扮埗缁勪欢鐨勮瀵熻€呫€俉atcher.prototype.cleanupDeps=functioncleanupDeps(){vari=this.deps.length;while(i--){vardep=this.deps[i];濡傛灉(!this.newDepIds.has(dep.id)){dep.removeSub(this);}}vartmp=this.depIds;this.depIds=this.newDepIds;this.newDepIds=tmp;this.newDepIds.clear();tmp=this.deps;this.deps=this.newDeps;this.newDeps=tmp;this.newDeps.length=0;};鑷充簬cleanupDeps鏂规硶锛屾槸鐢ㄦ潵鏇存柊灞炴€у搴旂殑depsubscriber涓殑watcher瀵硅薄銆倂iew涓嶉渶瑕佷緷璧朼ttribute锛岀浉搴旂殑watcher浠巇ep涓Щ闄わ紝watcher涓殑newDepIds姣忔淇濆瓨鏈€鏂扮殑depid闆嗗悎銆備緥濡傦紝瀵逛簬涓€涓敱v-if鎺у埗鐨勮妭鐐圭粍浠讹紝褰搒howChild鐨勫€肩敱true鍙樹负false鏃讹紝鐢变簬瀛愮粍浠朵笉鍐嶉渶瑕佹覆鏌擄紝鎵ц瀹宑leanupDeps鍚庡氨浼氬彇娑堝childVal鐨勮闃呫€?Parent>{{childVal}}瑙嗗浘鏇存柊濡備笂銆傛墽琛寀pdateComponent鍚庯紝娓叉煋瑙嗗浘銆傚綋涓€涓璞′唬鐞嗙殑鏁版嵁鏇存柊鏃讹紝鎵цset鏂规硶锛宒ep瑙﹀彂notify鏂规硶閫氱煡鎵€鏈墂atcher瑙傚療鑰呮墽琛寀pdate锛岀敓鎴愭柊vNode锛岄噸鏂版敹闆嗕緷璧栫瓑锛宲atchdiffs鏂版棫vNode锛屽苟鏇存柊宸紓鐨勮鍥俱€俈ue3閮藉嚭鏉ヤ簡锛屾€庝箞杩樺湪鍐橵ue2鐨勬€荤粨锛熷锛屾垜瑙夊緱鐜板湪涓嶆暣鐞嗗氨娌℃湁鏈轰細浜嗮煇躲€傚懙鍛碉紝濡傛湁閿欒锛岃鎸囧嚭銆?/p>