ngAfterViewInit( ) to early /// ngFor和异步网络请求导致无法选中目标元素的问题

news2024/12/1 10:26:01

今天遇到的最无语的问题:

angular 8版本以上,我在ngafterViewInit()中选取元素选取不到,加上setTimeOut()之后才可以选中

网上的解释:

Angular的ngAfterViewInit生命周期钩子是在组件视图的子视图初始化完成之后被调用的。但是如果您遇到了在ngAfterViewInit中某些元素仍未完全初始化的问题,可能是因为这些元素在ngAfterViewInit被调用时还没有完成初始化。

这通常是因为您的组件视图包含异步操作,例如使用*ngIf*ngForsetTimeout等等。这些操作会导致元素的延迟初始化,并且可能会影响到ngAfterViewInit的调用时机。

为了解决这个问题,您可以考虑使用ngAfterViewChecked生命周期钩子。ngAfterViewChecked会在每次组件视图检查完成之后被调用,因此它可以确保在视图元素完全初始化之后再执行某些操作。

但需要注意的是,使用ngAfterViewChecked可能会导致性能问题,因为它会在每次变更检测周期中被调用,这可能会增加应用程序的负载。

总之,如果您遇到了ngAfterViewInit中某些元素还未完成初始化的问题,可以尝试使用ngAfterViewChecked或者调整您的代码,以确保异步操作在视图元素完成初始化之后再执行。

结果代码检查,确实是使用了 *ngfor 的嵌套导致,并且使用setTimeout 之后可解决。

但是

前端体验不好,有明显延迟,

并且尝试使用ngAfterViewChecked后出现严重性能问题,当我使用 RXJS进行消息流通知时,出现了无限次调用。

ngAfterViewInit() 生命周期钩子在 Angular 渲染视图之前就会被触发,此钩子函数不是应该在视图渲染完毕后触发吗

ngAfterViewInit是Angular中的一个生命周期钩子函数,它会在组件的视图初始化完成后被调用。也就是说,当组件的模板和视图组成的DOM树渲染完成并且所有子组件都已经初始化完成后,ngAfterViewInit函数会被触发。

至于异步操作是否会影响ngAfterViewInit函数的调用,答案是:取决于异步操作的具体实现方式。如果异步操作是通过Angular的异步服务(例如HttpClient)来实现的,那么它们不会影响ngAfterViewInit函数的调用。

但是,如果使用了JavaScript原生的异步API(例如setTimeoutsetInterval),那么它们可能会在视图初始化完成之前就被触发,从而导致ngAfterViewInit函数无法正常执行。

核心原因:

这是因为 Angular 在渲染视图时使用了单向数据绑定和变更检测机制,这些机制依赖于视图已经完全初始化。如果在视图尚未完全初始化时尝试访问元素或进行其他操作,可能会导致错误或不一致的行为。因此,我们需要确保在视图初始化完成后再进行任何操作。

当 Angular 渲染组件视图时,它会执行以下步骤:

1. Angular 解析组件模板,并根据模板中的指令和数据绑定创建 DOM 元素。
2. Angular 将这些 DOM 元素插入到文档中,并将其与组件实例关联起来。
3. Angular 启动变更检测机制,以便在组件状态发生变化时更新视图。

在这个过程中,Angular 会使用单向数据绑定和变更检测机制来确保组件状态和视图保持同步。这意味着,在视图初始化完成之前,组件状态可能会发生变化,但这些变化不会立即反映在视图中。

如果您在 `ngAfterViewInit()` 生命周期钩子中尝试访问元素或进行其他操作,而这些操作需要在视图初始化完成后才能执行,那么可能会导致错误或不一致的行为。例如,如果您尝试在视图初始化完成之前获取元素的引用,那么该元素可能尚未被创建,从而导致访问错误或返回 `null`。

在 Angular 中,组件状态指的是组件类中的属性和方法。当组件状态发生变化时,这些变化可能会影响组件的行为或外观。例如,当用户单击按钮时,组件可能会将某个属性的值更改为新值。

与此同时,视图是与组件状态相关联的。当组件状态发生变化时,Angular 会使用变更检测机制来检测这些变化,并更新视图以反映这些变化。这意味着,当组件状态发生变化时,视图也应该随之更新。

但是,在视图初始化完成之前,组件状态可能会发生变化,但这些变化不会立即反映在视图中。这是因为 Angular 的变更检测机制需要一些时间来检测状态变化并更新视图。在这段时间内,视图可能会显示旧的状态,而不是最新的状态。

例如,假设您有一个组件,其中包含一个按钮和一个计数器属性。当用户单击按钮时,计数器属性的值会增加。如果您在 `ngAfterViewInit()` 生命周期钩子中尝试访问计数器属性的值,那么您可能会发现该值仍然是旧的值,而不是最新的值。这是因为视图尚未完全初始化,变更检测机制尚未检测到计数器属性的变化。

为了确保在视图初始化完成后访问最新的组件状态,请使用 `setTimeout()` 函数将操作推迟到下一个 JavaScript 事件循环中。这样可以确保 Angular 的变更检测机制已经完成,并且视图已经更新以反映最新的组件状态。

为了避免这种情况,您可以使用 `setTimeout()` 函数来将操作推迟到下一个 JavaScript 事件循环中。这样可以确保视图已经渲染完成,并且任何异步操作都已经完成。另外,您还可以使用 `ViewChild` 装饰器来获取元素引用,以避免在 `ngAfterViewInit()` 生命周期钩子中尝试访问元素时出现问题。

个人总结理解:

我使用ngfor来循环出 网络请求的来的数据,但是这个请求是一个 Observable,当我在ngAfterInit中去获取的时候,尚未走到下一个事件循环中(这个事件循环就是网络请求后的赋值),对于Angualr来说,视图确实是已经渲染完毕了,因为这个事件循环中,ngFor没有得到任何数据

。此时查询到dom为null,那么当下一个事件循环后,dom被渲染且赋值,并且同步到html内。这时我对ngAfterInit()中的 querySelecter()方法套上一层 setTimeOut(),是最后执行的事件循环。

衍生的问题:确定事件循环执行的顺序

在 JavaScript 中,`setTimeout()` 函数会将回调函数添加到事件队列中,并在指定的时间间隔后执行。如果您在代码中使用多个 `setTimeout()` 函数,那么这些函数的回调函数将按照它们被添加到事件队列中的顺序执行。

例如,假设您有以下代码:

console.log('Start');

setTimeout(() => {
  console.log('First');
}, 1000);

setTimeout(() => {
  console.log('Second');
}, 500);

console.log('End');

在这个例子中,`console.log()` 函数会输出 `Start` 和 `End`,然后将两个 `setTimeout()` 函数添加到事件队列中。第一个 `setTimeout()` 函数将在 1000 毫秒后执行,第二个 `setTimeout()` 函数将在 500 毫秒后执行。因此,输出顺序应该是:

Start
End
Second
First

请注意,由于 `setTimeout()` 函数的执行时间是不确定的,因此输出顺序可能会有所不同。但是,回调函数的执行顺序始终与它们被添加到事件队列中的顺序相同。

如果您需要确保一个回调函数在另一个回调函数之后执行,可以将第二个回调函数作为第一个回调函数的一部分执行。例如:

setTimeout(() => {
  console.log('First');
  setTimeout(() => {
    console.log('Second');
  }, 500);
}, 1000);

在这个例子中,第二个 `setTimeout()` 函数被添加为第一个 `setTimeout()` 函数的一部分,并在第一个回调函数执行后立即执行。这样可以确保第二个回调函数在第一个回调函数之后执行。

衍生问题的变形:angular的生命周期是一个事件循环吗?如果是,那么事件循环A中添加事件循环B,执行顺序是什么?

可以将 Angular 的生命周期钩子看作一个事件循环,因为它们定义了组件在不同时间点执行的操作。每个生命周期钩子都代表了一个特定的时间点,例如组件初始化、视图初始化、变更检测等。当 Angular 应用程序运行时,它会按照生命周期钩子定义的顺序依次执行这些操作。

在 Angular 中,每个生命周期钩子都有一个特定的目的。例如:

- `ngOnInit()` 生命周期钩子在组件初始化时执行,用于初始化组件属性和服务。
- `ngAfterViewInit()` 生命周期钩子在视图初始化完成后执行,用于访问视图元素和进行其他操作。
- `ngOnChanges()` 生命周期钩子在组件输入属性发生变化时执行,用于响应输入属性的变化。

通过按照生命周期钩子定义的顺序执行这些操作,Angular 可以确保组件和视图始终保持同步。例如,在 `ngAfterViewInit()` 生命周期钩子中访问视图元素可以确保视图已经完全初始化,并且元素已经被创建。

因此,您可以将 Angular 的生命周期钩子看作一个事件循环,其中每个生命周期钩子代表了一个特定的事件。您可以在这些事件中执行您需要的操作,并确保这些操作与组件和视图状态保持同步。

那么问题就变成了:事件循环A中添加事件循环B,执行顺序是什么

在 JavaScript 中,事件循环是通过事件队列实现的。当代码执行时,它会将回调函数添加到事件队列中,并在主线程完成当前任务后执行这些回调函数。如果在事件循环 A 中添加了一个事件循环 B,那么事件循环 B 的回调函数将被添加到事件队列 A 的末尾。

例如,假设您有以下代码:

console.log('Start');

setTimeout(() => {
  console.log('First');
}, 1000);

setTimeout(() => {
  console.log('Second');
}, 500);

setTimeout(() => {
  console.log('Third');
  setTimeout(() => {
    console.log('Fourth');
  }, 1000);
}, 1500);

console.log('End');

在这个例子中,代码会先输出 `Start` 和 `End`,然后将三个 `setTimeout()` 函数添加到事件队列中。第一个 `setTimeout()` 函数将在 1000 毫秒后执行,第二个 `setTimeout()` 函数将在 500 毫秒后执行,第三个 `setTimeout()` 函数将在 1500 毫秒后执行,并在回调函数中添加了一个新的 `setTimeout()` 函数。

因此,事件循环的执行顺序如下:

1. 输出 `Start`。
2. 输出 `End`。
3. 等待 500 毫秒,然后输出 `Second`。
4. 等待 500 毫秒,然后输出 `First`。
5. 等待 1000 毫秒,然后输出 `Third`。
6. 等待另外 1000 毫秒,然后输出 `Fourth`。

请注意,事件循环 B 的回调函数会在事件循环 A 的回调函数之后执行,因为它们被添加到了事件队列 A 的末尾。因此,在上面的示例中,`Third` 和 `Fourth` 的输出顺序取决于它们被添加到事件队列的时间。

规约这个问题:

最终结论,如果在事件循环 A 中添加了一个事件循环 B,那么事件循环 B 的回调函数将被添加到事件队列 A 的末尾。

好。ngInit()中添加了一个http异步请求,相当于在事件循环A中添加了一个事件循环B,那么这个http请求是在最后执行的,换句话说,http 在 ngAfterViewInit()之后,所以,这就是为什么ngAfterViewInit()无法选中需要的元素。

同理,对 querySelecter()添加setTimeOut之后,为什么要设置3000ms才能获取目标dom,10ms就获取不到?因为事件循环在指定的时间间隔后执行,如果http请求对完成事件晚于querySelecter,那么确实是获取不到的。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/768328.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uniapp | 查看ios打包后的Info.plist文件

最近在用 uni 开发 ios 的时候给项目添加了自定义的 Info.plist 文件,但是打包后发现并没有生效,才有了查看打包后的 Info.plist 文件想法。 HBuilderX3.6.5起,支持直接在应用项目中配置 iOS 平台的 Info.plist 和 资源文件(Bundl…

使用 uiautomator2+pytest+allure 进行 Android 的 UI 自动化测试

目录 前言: 介绍 pytest uiautomator2 allure 环境搭建 pytest uiautomator2 allure pytest 插件 实例 初始化 driver fixture 机制 数据共享 测试类 参数化 指定顺序 运行指定级别 重试 hook 函数 断言 运行 运行某个文件夹下的用例 运行某…

unity 2019 内置渲染管线 光照与Lighting面板 参数详解

文章目录 前言一 Unity的光照 与 烘焙光照1 unity完整的光照组成2 光的亮度与颜色3 全局光照直接光间接光5 间接光≠光照贴图 二 色彩空间与自动烘焙1 unity的色彩空间2 自动烘焙光照 三 烘焙1 什么是烘焙,烘焙的是什么2 如何进行烘焙3 烘焙的优点和缺点4 查看光照贴…

Redis : zmalloc.h:50:31: 致命错误:jemalloc/jemalloc.h:没有那个文件或目录

In file included from adlist.c:34:0: zmalloc.h:50:31: 致命错误&#xff1a;jemalloc/jemalloc.h&#xff1a;没有那个文件或目录 #include <jemalloc/jemalloc.h> 解决 : 如上图使用命令 make MALLOClibc

2023杭电多校(一)

1002 City Upgrading 类似题及其题解 City Upgrading Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 524288/131072 K (Java/Others) Total Submission(s): 306 Accepted Submission(s): 78 Problem Description The city where crazyzhk resides is stru…

分布式事务几种实现方案

前言 分布式事务&#xff1f; 分布式事务是指涉及多个参与者的事务&#xff0c;这些参与者可能分布在不同的计算机、进程或者网络中。分布式事务需要保证ACID属性&#xff0c;即原子性、一致性、隔离性和持久性 解释 现在我们接触的系统基本上都是分布式系统&#xff0c;并且每…

计算几何(二维),定理及证明(持续更新中..)

注&#xff1a;定理来自这篇博客&#xff0c;本文注重证明 向量基本运算 加法 向量 a ⃗ ( x 1 , y 1 ) , b ⃗ ( x 2 , y 2 ) \vec{a}\left(x_1,y_1\right),\vec{b}\left(x_2,y_2\right) a (x1​,y1​),b (x2​,y2​) 则 a ⃗ b ⃗ ( x 1 x 2 , y 1 y 2 ) \vec{a}\…

P7 第二章 电阻电路的等效变换

1、等效变换应用举例 化简套路&#xff1a; 电压源与其串联的电阻&#xff0c;可以等效为电流源并联电阻&#xff0c;然后电流源就可以拿去合并电路中的&#xff0c;与之并联的电流&#xff0c;电阻则可以拿去合并与之并联的电阻。 公式法&#xff1a; 就是根据端的电压与端的…

第一节 C++ 变量

文章目录 1. Visual Studio Community 安装1.1. Visual Studio 介绍1.2. Visual Studio的安装1.3 Visual Studio创建与使用1.3.1 创建一个工程项目1.3.2 新建一个C文件1.3.3 编写执行文件 2. Dev-C 安装(初学者建议使用)2.1 Dev-C 介绍2.2 Dev-C 安装2.3 Dev-C 快捷键使用 3. 认…

数学建模常用模型(九) :偏最小二乘回归分析

数学建模常用模型&#xff08;九&#xff09; &#xff1a;偏最小二乘回归分析 偏最小二乘回归&#xff08;Partial Least Squares Regression&#xff0c;PLS Regression&#xff09;是一种常用的统计建模方法&#xff0c;用于解决多元线性回归中自变量间高度相关的问题。在偏…

【java】三大容器类(List、Set、Map)的常用实现类的特点

三大容器类&#xff08;List、Set、Map&#xff09;的常用实现类的特点 简介 本文总结三大容器类&#xff08;List、Set、Map&#xff09;的常用实现类&#xff08;ArrayList、Vector、LinkedList、HashSet、HashMap、HashTable&#xff09;的特点 一、List部分 1、ArrayLi…

C# DlibDotNet 人脸识别、人脸68特征点识别、人脸5特征点识别、人脸对齐,三角剖分,人脸特征比对

人脸识别 人脸68特征点识别 人脸5特征点识别 人脸对齐 三角剖分 人脸特征比对 项目 VS2022.net4.8OpenCvSharp4DlibDotNet Demo下载 代码 using DlibDotNet.Extensions; using DlibDotNet; using System; using System.Collections.Generic; using System.ComponentModel; …

学堂在线数据结构(上)(2023春)邓俊辉 课后作业错题整理

The reverse number of a sequence is defined as the total number of reversed pairs in the sequence, and the total number of element comparisons performed by the insertion sort in the list of size n is: 一个序列的逆序数定义为该序列中的逆序对总数&#xff0c;…

transformer Position Embedding

这是最近一段很棒的 Youtube 视频&#xff0c;它深入介绍了位置嵌入&#xff0c;并带有精美的动画&#xff1a; Transformer 神经网络视觉指南 -&#xff08;第 1 部分&#xff09;位置嵌入 让我们尝试理解计算位置嵌入的公式的“sin”部分&#xff1a; 这里“pos”指的是“单词…

自定义view(一)----自定义TextView

自定义view也算是Android的一大难点&#xff0c;里面涉及到很多值得学习的地方&#xff0c;我会在接下来写一系列文章去介绍它&#xff0c;本篇文章以自定义一个TextView为例。 View的构造方法 自定义view之前我们先了解view的四个构造方法&#xff0c;自定义view无非就是新建一…

R语言逻辑回归(Logistic Regression)、回归决策树、随机森林信用卡违约分析信贷数据集...

原文链接&#xff1a;http://tecdat.cn/?p23344 本文中我们介绍了决策树和随机森林的概念&#xff0c;并在R语言中用逻辑回归、回归决策树、随机森林进行信用卡违约数据分析&#xff08;查看文末了解数据获取方式&#xff09;&#xff08;点击文末“阅读原文”获取完整代码数据…

MVSNet、PatchMatchNet中的 eval.sh文件超参数解释

下面以PatchMatchNet为例, 打开PatchMatchNet程序中的 eavl.sh文件, 可以看到文件设置了数据集路径,及超参数设置(超参数,也可以不写,会使用默认参数) 上图中各参数意思如下: 执行文件python eval.py; 数据集加载方方式使用dtu_yao_eval ; batch_size=1 ,视图数N设…

【C++】命名空间 ( namespace )

目录搁这 什么是命名空间命名空间的作用如何定义命名空间命名空间的种类如何使用命名空间内的成员作用域限定符命名空间展开命名空间全部展开命名空间部分展开 总结 什么是命名空间 命名空间是一种用来避免命名冲突的机制&#xff0c;它可以将一段代码的名称隔离开&#xff0c…

中国地图使用心得

中国地图使用心得 注册地图是注册在echarts对象上而非 自己构建的echarts dom上、。 请求本地json文件 ​ vue项目的public打包时不会动&#xff0c;所以线上和本地地址直接指向了public同级目录&#xff0c;请求时直接相对路径 绘制中国地图时&#xff0c;如何在各个省会地方…