我正在一个现有项目中浏览Angular代码,并在以下代码段中找到。
我们正在使用Angular material datatable
在页面上呈现视图
export class Component implements OnInit,AfterViewInit{
private dataSource: MatTableDataSource<Product> = null;
@ViewChild(MatPaginator) paginator: MatPaginator;
columnsToDisplay = ['productId','productname'];
constructor(private _service : DataService) { }
ngOnInit() {
this._service.getProducts().subscribe(
((data : Product[]) => this.dataSource = new MatTableDataSource(data)),
() => console.log('THIS IS ERROR')
);
setTimeout(() => this.dataSource.paginator = this.paginator);
//this.dataSource.paginator = this.paginator;
}
ngAfterViewInit() {
this.dataSource.paginator = this.paginator;
}
}
我的问题是:
1)由于this.service.getData()
返回一个Observable
,并且只要subscribe
可用,HttpResponse
就会被异步调用,
setTimeout
函数内部的操作是否将被称为仅在之后?subscribe
方法被调用?
2)我已经看到ngAfterViewInit
方法还包含与setTimeout
方法中的ngOnInit
方法相同的代码
3)但是,当此方法称为(ngAfterViewInit)
时,this.products
仍然为NULL,表示尚未将subscribe称为'
4)是在setTimeout
方法内部调用ngOnInit
的原因吗?
5)如果是这种情况,ngAfterViewInit
方法的用途是什么?
答案 0 :(得分:1)
1)这取决于。订阅仅在操作完成后才执行代码。因此,this.service.getData()
完成工作后。 setTimeout在延迟后执行该工作。如果订阅所需的时间少于setTimeout,则将首先执行。
2)也许您正试图注意到函数执行的时间?
3)AfterViewInit被多次触发。您可以像这样if(!!something)
进行检查,然后执行一些代码。
4)您应该始终避免使用settimeout(仅将其用于调试目的)。
编辑:
ngOnInit(){
this._service.getProducts().subscribe(
((data : Product[]) => this.dataSource = new MatTableDataSource(data)),
() => console.log('THIS IS ERROR')
);
setTimeout(() => this.dataSource.paginator = this.paginator);
//this.dataSource.paginator = this.paginator;
} `
让我们简单地讲一下这段代码:
ngOnInit() {
this.service.doStuff()
.subscribe(result => {
this.functionA();
},
err => {
//Do other stuff in case of an error
});
this.functionB();
}
functionA(){
console.log("Hello,");
}
functionB(){
console.log("world!");
}
此代码的输出将是:
world!Hello,
但是为什么?
那是因为observable
模式。
您可以想象,当您与两个人同行时:一个会英语,另一个不会。因此,即使您说“你好吗?”首先是一个不懂英语的人,他将需要时间来理解你说的话并回答你。同时,另一个人(非常懂英语)会立即回答您。
functionA
和functionB
的示例相同。订阅已捕获某些内容时,仅执行功能。这就是为什么不首先触发它的原因。您可以看到在此处放置调试点:
ngOnInit() {
this.service.doStuff()
.subscribe(result => {
---> this.functionA();
},
err => {
//Do other stuff in case of an error
});
---> this.functionB();
}
希望对此进行很好的解释。
现在让我们继续,让我们使用超时时间:
ngOnInit() {
this.service.doStuff()
.subscribe(result => {
this.functionA();
},
err => {
//Do other stuff in case of an error
});
settimeout(() => {
this.functionB();
}, 500);
}
哪个功能将首先执行?
剧透:你不知道。
如果您想知道为什么,这很容易:您完全知道functionB将在500ms之后被调用,但是您不知道将使用预订准备多少时间。因此,如果幸运的话,您的订阅通常需要大约500毫秒才能完成,因此您可以尝试重新加载页面几次,有时会看到Hello, world!
,有时会看到world!Hello,
。
为了更好地回答您的问题:我真的不知道您为什么要像这样放置代码,实际上不知道。
ngAfterViewInit是一个life-cycle
,位于ngOnInit之后,称为,在Angular完全初始化组件的视图之后执行该逻辑。
答案 1 :(得分:1)
我将尝试简化描述:
setTimeout将内部函数放在javascript队列的末尾,因此当javascript进程运行时,它将从堆栈中弹出并调用该操作。仅当堆栈为空时,队列中的所有内容才会被调用。因此setTimeout
告诉javascript保留这段代码,直到完成工作为止。
可订阅和可观察:可观察是异步数据结构,因此一旦订阅它,您将永远无法花费多少时间来调用subscribe方法。换句话说,只有在http响应返回的情况下,subscribe才会被调用。
回到您的问题:您不知道何时调用setTimeout代码,但从理论上讲,它将在订阅之前被调用(JavaScript引擎比http响应速度更快)。
如果仅在从http请求中获取数据后才需要初始化某些数据表结构,则应将其放入subscribe
方法中,而无需setTimeout。
ngAfterViewInit
用于通知开发人员在此阶段您的view
已准备就绪,您可以使用elementRef作为示例。
ngOnInit
用来表示开发人员所有输入和指令...等。
答案 2 :(得分:0)
1。否,setTimeout将仅被调用一次,然后在其上下文之外进行订阅。
2。。由于异步更新,如果我们异步更新属性,则在验证循环运行时不会更新值,并且不会出错。
3。。只有在ngAfterViewInit之后,ViewChild才可用。它会在创建视图时填充子级,因此可以更早使用它们。
4。。ngOnInit生命周期挂钩在DOM更新操作之前被触发,不会产生任何错误。处理绑定后,将触发ngOnInit生命周期挂钩。最初呈现视图时即调用ngAfterViewInit,即在创建组件的视图及其子视图之后调用。
5。。应在组件的视图及其子视图创建之后调用ngAfterViewInit(),最重要的是,在父级的ngAfterViewInit()之前调用子项的ngAfterViewInit()。