Angular变更检测中的DOM更新机制是什么


这篇文章主要介绍“Angular变更检测中的DOM更新机制是什么”,在日常操作中,相信很多人在Angular变更检测中的DOM更新机制是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Angular变更检测中的DOM更新机制是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧! 变更检测是Angular中很重要的一部分,也就是模型和视图之间保持同步。在日常开发过程中,我们无需了解变更检测,因为Angular都帮我们完成了这一部分工作,让开发人员更加专注于业务实现,提高开发效率和开发体验。但是如果想要深入使用框架,或者想要写出高性能的代码而不仅仅只是实现了功能,就必须要去了解变更检测,它可以帮助我们更好的理解框架,调试错误,提高性能等。我们先来看一个小例子。当我们点击按钮的时候,改变了name属性,同时DOM自动被更新成新的name值。那现在有一个问题,如果我改变name的值后,紧接着把DOM中的innerText输出出来,它会是什么值呢?

import{Component,ViewChild,ElementRef}from'@angular/core';

@Component({
selector:'my-app',
templateUrl:'./app.component.html',
styleUrls:['./app.component.css']
})
exportclassAppComponent{
name='Empty';

@ViewChild('textContainer')textContainer:ElementRef;

normalClick():void{
this.name='HelloAngular';

console.log(this.textContainer.nativeElement.innerText);
}
}

你答对了吗?那这两段代码中到底发生了什么呢?如果我们用原生JS来编写这段代码,那么点击按钮后的视图肯定不会发生任何变化,而在Angular中却让视图发生了变化,那它为什么会自动把视图更新了呢?这离不开一个叫做zone.js的库,简单来说,它是对发生值改变的事件做了一些处理,这个会在后面的部分详细讲解,这里暂时知道这个就可以了。如果我不想让这个库做这些处理,Angular还为我们提供了禁用zone.js的方法。可以在main.ts中设置禁用zone.js。

import{enableProdMode}from'@angular/core';
import{platformBrowserDynamic}from'@angular/platform-browser-dynamic';

import{AppModule}from'./app/app.module';
import{environment}from'./environments/environment';

if(environment.production){
enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule,{
ngZone:'noop'
})
.catch(err=>console.error(err));

当我们禁用zone.js,视图并未发生更新。到源码里找一下视图更新的相关代码。

*/
classApplicationRef{
/**@internal*/
constructor(_zone,_injector,_exceptionHandler,_initStatus){
this._zone=_zone;
this._injector=_injector;
this._exceptionHandler=_exceptionHandler;
this._initStatus=_initStatus;
/**@internal*/
this._bootstrapListeners=[];
this._views=[];
this._runningTick=false;
this._stable=true;
this._destroyed=false;
this._destroyListeners=[];
/**
*Getalistofcomponenttypesregisteredtothisapplication.
*Thislistispopulatedevenbeforethecomponentiscreated.
*/
this.componentType免费云主机域名s=[];
/**
*Getalistofcomponentsregisteredtothisapplication.
*/
this.components=[];
this._onMicrotaskEmptySubscription=this._zone.onMicrotaskEmpty.subscribe({
next:()=>{
this._zone.run(()=>{
this.tick();
});
}
});
...
}

/**
*Invokethismethodtoexplicitlyprocesschangedetectionanditsside-effects.
*
*Indevelopmentmode,`tick()`alsoperformsasecondchangedetectioncycletoensurethatno
*furtherchangesaredetected.Ifadditionalchangesarepickedupduringthissecondcycle,
*bindingsintheapphaveside-effectsthatcannotberesolvedinasinglechangedetection
*pass.
*Inthiscase,Angularthrowsanerror,sinceanAngularapplicationcanonlyhaveonechange
*detectionpassduringwhichallchangedetectionmustcomplete.
*/
tick(){
NG_DEV_MODE&&this.warnIfDestroyed();
if(this._runningTick){
consterrorMessage=(typeofngDevMode==='undefined'||ngDevMode)?
'ApplicationRef.tickiscalledrecursively':
'';
thrownewRuntimeError(101/*RuntimeErrorCode.RECURSIVE_APPLICATION_REF_TICK*/,errorMessage);
}
try{
this._runningTick=true;
for(letviewofthis._views){
view.detectChanges();
}
if(typeofngDevMode==='undefined'||ngDevMode){
for(letviewofthis._views){
view.checkNoChanges();
}
}
}
catch(e){
//Attention:Don'trethrowasitcouldcancelsubscriptionstoObservables!
this._zone.runOutsideAngular(()=>this._exceptionHandler.handleError(e));
}
finally{
this._runningTick=false;
}
}

}

大致解读一下,这个ApplicationRef是Angular整个应用的实例,在构造函数中,zone(zone库)的onMicrotaskEmpty(从名字上看是一个清空微任务的一个subject)订阅了一下。在订阅里,调用了tick(),那tick里做了什么呢思考: 上次说了最好订阅不要放到constructor里去订阅,这里怎么这么不规范呢?当然不是,上次我们说的是Angular组件里哪些应该放constructor,哪些应该放ngOnInit里的情况。但这里,ApplicationRef人家是一个service呀,只能将初始化的代码放constructor。在tick函数里,如果发现这个tick函数正在执行,则会抛出异常,因为这个是整个应用的实例,不能递归调用。然后,遍历了所有个views,然后每个view都执行了detectChanges(),也就是执行了下变更检测,什么是变更检测,会在后面详细讲解。紧接着,如果是devMode,再次遍历所有的views,每个view执行了checkNoChanges(),检查一下有没有变化,有变化则会抛错(后面会详细说这个问题,暂时跳过)。那好了,现在也知道怎么能让它更新了,就是要调用一下ApplicationReftick方法。

import{Component,ViewChild,ElementRef,ApplicationRef}from'@angular/core';
@Component({
selector:'app-root',
templateUrl:'./app.component.html',
styleUrls:['./app.component.scss']
})
exportclassAppComponent{
name='Empty';

@ViewChild('textContainer')textContainer:ElementRef={}asany;

constructor(privateapp:ApplicationRef){}

normalClick():void{
this.name='HelloAngular';

console.log(this.textContainer.nativeElement.innerText);

this.app.tick();
}
}

果然,可以正常的更新视图了。到此,关于“Angular变更检测中的DOM更新机制是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注百云主机网站,小编会继续努力为大家带来更多实用的文章!

相关推荐: Vue.js怎么实现文件上传压缩优化

本篇内容介绍了“Vue.js怎么实现文件上传压缩优化”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!两种方法 :第1种是借助canvas的封装的文件压缩上传第2种…

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

(0)
打赏 微信扫一扫 微信扫一扫
上一篇 02/27 15:03
下一篇 02/27 15:03

相关推荐