【问题标题】:SetTimeOut function inside ngOnInit of Angular component while using Angular Material DataTable使用 Angular Material DataTable 时,Angular 组件的 ngOnInit 内的 SetTimeOut 函数
【发布时间】:2018-09-24 12:15:24
【问题描述】:

我正在查看我现有项目之一中的 Angular 代码,并在 sn-p 下方找到。 我们正在使用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) 这就是在ngOnInit 方法中调用setTimeout 的原因吗?

5)如果是这种情况,ngAfterViewInit方法有什么用?

【问题讨论】:

  • 据我所知,没有理由拥有setTimeouts 中的任何一个。似乎已经为产品设置了默认值,但这不需要异步完成。
  • 我在我的问题中添加了更多细节。请检查

标签: javascript angular angular-material settimeout


【解决方案1】:

我会尽量简化描述:

  1. setTimeout 将 inside 函数放在 javascript 队列的末尾,因此当 javascript 进程运行时,它将从堆栈中弹出并调用该操作。只有当堆栈为空时,才会调用队列中的任何内容。所以setTimeout 告诉 javascript 保存这段代码,直到你完成工作。

  2. subscribe 和 observable:observable 是异步数据结构,所以一旦你订阅它,你就永远无法知道调用 subscribe 方法需要多少时间。换句话说,只有在 http 响应返回时才会调用 subscribe。

回到你的问题:你不知道你的 setTimeout 代码何时被调用,但理论上它会在订阅之前被调用(javascript 引擎比 http 响应更快)。

如果你需要在从http请求中获取数据后才需要初始化一些数据表结构,你应该把它放在subscribe方法中,不需要setTimeout。

ngAfterViewInit 被 angular 用来告诉开发者,在这个阶段你的view 已经准备好了,你可以作为一个例子使用 elementRef。

ngOnInit 被 Angular 用来告诉开发者所有的输入和指令……等等。

【讨论】:

  • 但是当调用 ngAfterViewInit 时为什么我的 this.dataSource 是 NULL 呢?我应该如何确保 this.dataSource.paginator = this.paginator;赋值发生在 this.dataSource 获得值之后。当前的鳕鱼似乎无法正常工作
  • ` this._service.getProducts().subscribe( ((data : Product[]) => {this.dataSource = new MatTableDataSource(data)}; this.dataSource.paginator = this.paginator ;), () => console.log('这是错误') );`
  • 很高兴为您提供帮助:)
【解决方案2】:

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 模式。

您可以想象,当您与两个人同行时:一个会英语,一个不会。所以即使你说“你好吗?”首先对于不懂英语的人,他需要时间来理解你说了什么并回答你。同时,另一个人(英语很好)会立即回答你。

functionAfunctionB 的例子是一样的。 FunctionA仅在订阅捕获某些内容时执行。这就是为什么它没有首先被解雇。可以看到这里放了一个调试点:

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);
        }

哪个函数会先执行?

剧透:你不知道。

如果您想知道为什么,这很简单:您确切地知道函数 B 将在 500 毫秒后被调用,但您不知道要使用多少时间才能准备好订阅。所以如果你运气好,你的订阅通常需要大约 500ms 才能完成,你可以尝试多次重新加载页面,有时你会看到Hello, world!,有时你会看到world!Hello,

为了更好地回答你的问题:我真的不知道你为什么把代码写成这样,真的不知道。

ngAfterViewInit 是一个名为 ngOnInit 之后的life-cycle,并在 Angular 完全初始化组件视图后执行逻辑。

【讨论】:

  • 我已修改问题以提供更多详细信息
【解决方案3】:

1. 不,setTimeout 只会被调用一次,并且在订阅之前作为它的上下文之外。

2.由于异步更新,如果我们异步更新属性,则在验证循环运行时不会更新值并且我们不会出错。

3. ViewChild 仅在 ngAfterViewInit 之后可用。它在创建视图时填充子项,因此它们更早可用。

4. ngOnInit 生命周期钩子在 DOM 更新操作之前触发,不会报错。处理完绑定后触发 ngOnInit 生命周期钩子。 ngAfterViewInit 在最初呈现视图时调用,即在创建组件视图及其子视图之后调用它。

5. ngAfterViewInit() 应该在组件的视图及其子视图创建之后调用,最重要的是子视图的 ngAfterViewInit() 在父组件的 ngAfterViewInit() 之前调用。

【讨论】:

    猜你喜欢
    • 2022-01-14
    • 2019-01-25
    • 1970-01-01
    • 2020-04-19
    • 1970-01-01
    • 2018-11-14
    • 2019-03-08
    • 2020-04-26
    • 2019-06-17
    相关资源
    最近更新 更多