GVKun编程网logo

整理AngularJS框架使用过程当中的一些性能优化要点(angularjs框架怎么搭)

20

对于整理AngularJS框架使用过程当中的一些性能优化要点感兴趣的读者,本文将提供您所需要的所有信息,我们将详细讲解angularjs框架怎么搭,并且为您提供关于Angular14inject函数使

对于整理AngularJS框架使用过程当中的一些性能优化要点感兴趣的读者,本文将提供您所需要的所有信息,我们将详细讲解angularjs框架怎么搭,并且为您提供关于Angular 14 inject 函数使用过程中的一些注意事项、angular 单元测试过程当中错误类型总结、angularjs – Angular.js 1.3 ng-bind中的一次性绑定、angularjs – 在Angular 1中是否存在单向绑定的性能优势的宝贵知识。

本文目录一览:

整理AngularJS框架使用过程当中的一些性能优化要点(angularjs框架怎么搭)

整理AngularJS框架使用过程当中的一些性能优化要点(angularjs框架怎么搭)

1. 简介

无论你正在编写一个旧的应用程序还是在一个大型应用中采用AngularJS,性能是一个重要的方面。了解是什么原因导致AngularJS应用程序慢下来非常重要,要知道,在开发过程中做出权衡是很重要的。本文将介绍一些AngularJS比较常见的性能问题,以及优化的建议。

2. 性能测试工具

本文采用jsPerf http://jsperf.com/ 性能测试的基准。

3. 软件性能

评价软件性能有两个基本的因素:

首先是算法的时间复杂度。一个简单的例子就是线性搜索和二分检索有着非常显著的性能差距。

第二个软件缓慢的原因被称为空间复杂度。这是一台电脑需要多少“空间”或内存运行你的应用程序。内存需求越多,运行速度就越慢。

4 Javascript的性能

有些性能问题不仅仅是Angular带来的,而是JavaScript本来就有的。

4.1 循环

避免在循环内部调用函数,可以移到外部调用。

rush:js;"> var sum = 0; for(var x = 0; x < 100; x++){ var keys = Object.keys(obj); sum = sum + keys[x]; }

上面的方面明显没有下面的快:

rush:js;"> var sum = 0; var keys = Object.keys(obj); for(var x = 0; x < 100; x++){ sum = sum + keys[x]; }

4.2 DOM访问

在获取DOM元素时要注意

rush:js;"> angular.element('div.elementClass')

这种方式是非常昂贵的。其实这在AngularJS中并不会引起太大的问题。但是留意一下是有好处的。DOM树要小,DOM的访问要尽可能的少。

4.3 变量作用范围垃圾回收

把你的变量作用范围限制地越紧密越好,这样垃圾回收器就可以更快地回收空间。注意下面的问题:

rush:js;"> function demo(){ var b = {childFunction: function(){ console.log('hi this is the child function') }; b.childFunction(); return b; }

当这个函数终上了,这里就没有到b的引用。b就会被回收了。但是如果有这样一行:

rush:js;"> var cFunc = demo();

这个引用就会阻止垃圾回收。要尽量避免这类引用。

4.4 数组和对象

这里有很多点:

比如:

rush:js;"> for (var x=0; x

比这一种快一点(注* arr为数组, obj为json对象)

rush:js;"> for (var x=0; x<100; x++) { i = obj[x].index; }

比这一种更快一点

rush:js;"> var keys = Object.keys(obj); for (var x = 0; x < keys.length; x++){ i = obj[keys[x]].index; }

5 重要的概念

我们已经讨论过有关JavaScript的性能,现在有必要看一看AngualrJS中的核心概念,看看它究竟是怎么运作的。

5.1 域(Scopes)和更新周期(Digest Cycle)

Angular的域本质上是一些JavaScript对象,它们从一些预定义的对象继承而来。基本上,小的域比大的域运行要快。

换句话说,每创建一个新的域,都会给垃圾回收器添加更多待回收的内容。

在写AngularJS应用中尤其要注意的一个核心概念和性能影响方面是更新周期(Digest Cycle)。实际上每一个域都会存放一个由方法组成的数组 $$watchers。

每当域中的一个值(属性)或绑定的DOM,如 ng-repeat,ng-switch 和 ng-if 等等,调用 $watch 时,一个函数(function)就会添加到相对应域中的$$watchers数组队列中。

当域中的值发生改变时,在$$watchers中所有的watchers函数都会被触发调用。并且当它们的任何一个修改了域中的某个值时,它们会被再次触发执行。

这个过程会一直循环下去直到$$watcher数组队列中不再做任何更改或抛出异常为止。

更外如果任何代码执行$scope.$apply(),都会触发更新周期。

最后一点是 $scope.evalAsync() 会在一个异步调用中执行,并且在当前和下个执行周期中,不会调用其的更新周期。

6. 在设计Angular时应该遵守的一般准则

6.1 大型对象和服务器调用

所以这些都告诉了我们什么?首先我们要尽可能地简化我们的对象。当对象是从服务器返回时,这一点尤为重要。

直接将数据库中的一行转换成对象只是临时性方案,因此不要使用.toJson().

只需要把Angular需要的属性值返回回来。

6.2 监视函数(Watching Functions)

另一个常见的问题是为观察者绑定的函数。不要将任何东西(ng-show,ng-repeat等等)直接绑定到一个函数。不要直接监视任何函数的返回值。该函数会在每个更新周期都执行,可能会降低你应用的速度。

6.3 监视对象(Watching Objects)

同样,Angular提供了第三个可选参数来监视整个对象的改动。将调用$watch的第三个参数设为true。这是一个非常可怕的想法。一个更好的解决办法是依靠服务和对象的引用,监视域之间的变化。

7 列表问题

7.1 长列表(Lists)

尽一些可能避免长列表。ng-repeat会进行了一些很重的DOM操作(更不用说对$$watchers的污染),所以无论是在分页或是在无限滚动中,尽量使用小型数据进行渲染。

7.2 过滤器(Filters)

要尽量避免使用过滤器。他们会在每个更新周期运行两次,每当发生任何改变时运行一次,另一次是收集更深层次的改变时触发。所以不要直接从内部列表中移除对象,使用CSS控制即可。(注* 用添加CSS类名去隐掉他们)

渲染时的 $index 值并不是真正的数组索引值,它豪无价值。但是排好序的数组索引,无法让你遍历到所有列表中的域。

7.3 更新 ng-repeat

当使用ng-repeat时要尽量避免对全局列表的刷新。ng-repeat会产生一个$$hashkey属性和一系统唯一的项。这意味着当你调用 scope.listBoundToNgRepeat = serverFetch() 时会引起对整个列表的重新刷新。会通知执行所有的watchers并触发每一个元素,这是非常消耗性能的。

这里有两种解决方案。一种是维护两个集合,和带有过虑器(filter)的ng-repeat(基本上需要自定义同步逻辑,因此算法更复杂,可维护性更差),另一种方案是使用track by去指定你自己的key(Angular 1.2 开始支持,只需要很少的同步逻辑)。

总之:

rush:js;"> scope.arr = mockServerFetch();

会比下面的这种慢

=0; i--){ var result = _.find(a,function(r){ return (r && r.trackingKey == scope.arr[i].trackingKey); }); if (!result){ scope.arr.splice(i,1); } else { a.splice(a.indexOf(scope.arr[i]),1); } } _.map(a,function(newItem){ scope.arr.push(newItem); });

这种

rush:js;">

比上面的慢些

rush:js;">

8 渲染问题

另一个引起Angular应用慢的原因是不正确地使用 ng-hide/ ng-show 或 ng-switch。

ng-hide 和 ng-show 简单地对CSS display属性进行切换。这意味着表面上看不见的东西其实还存在于域中, 所有的$$watchers还是会被触发。

ng-if 和 ng-switch实际上从DOM中完全移除了,相应的域也会被移除。性能差异显而易见。

9. 更新周期问题

9.1 绑定

尽量减少你的绑定。在Angular 1.3中这里有一个新的一次绑定语法,{{::scopeValue}}。它只会被域执行一次,并不添加到监视器要监视列表中(watcher array).

9.2 $digest() 和 $apply()

scope.$apply 是一个强大的工具,可以让你向Angular引入外部的值。本质上它会触发Angular的所有事件(例如ng-click)。问题是scope.$apply会从根域$rootScope开始,遍历所有的域链,触发每一个域。

scope.$digest只会执行指定域及其相关的域。两种性能差异不言自明。折中的方案是,不触发任何域等到下一个更新周期再更新。

9.3 $watch()

scope.$watch() 已经在很多场景被讨论过的。基本上scope.$watch是不好的设计的一个标志。如果你非要创建一个观察者。记住对它尽可能地解绑。你可以用$watch的返回函数解绑。

rush:js;"> var unbinder = scope.$watch('scopeValuetoBeWatcher',function(newVal,oldVal) {

});
unbinder(); //这一行将watcher从 $$watchers 中移除。

如果你不能早一点解绑,记住在 $on('$destroy') 中进行解绑。

9.4 $on,$broadcast 和 $emit

像$watch一样,他们都是一些很慢的事件,(有可能)遍历整个作用域。他们可能像GOTO一样,让你的程序无法调试。不过幸运地是像$watch一样,他们都可以在完全不需要的时侯解绑。比如在 $on('$destroy')中。

9.5 $destroy

像前面提到的那样,你应该在$on('$destroy')中解绑你所有的事件侦听器,取消任何$timeout的实例,或者任何其它异步执行的交互。这不仅仅是确保安全。还可以让你的域更快地被垃圾回收。不这样做,他们会一直在后台运行。直接你清空cpu和RAM。

另外,解绑DOM上的事件侦听器也非常重要,不这样做很可能在老式浏览器中引起内存泄露。

9.6 $evalAsync

scope.$evalAsync是一个强大的工具。它可以在当前域中执行,并不触发域的更新。evalAsync可以极大地提高你网页的性能。

10 指令问题

10.1 隔离的域(Isolate Scope)和Transclusion

域隔离和Transclusion是Angular最另人激动的特性,它们是Angular的核心组件。

但是这里也有一些权衡,指令不能直接创建一个替换他们父组元素的域。通过隔离的域或Transclusion我们可以创建一个新的对象去跟踪,添加新的监视器,但是这也会降低应用的性能。在添加之前应该仔细想一想有没有这个必要。

10.2 编绎周期

指令(Directive)的compile函数是在域被附加前操作DOM的完美功能(比如说绑定事件)。一个很重要的性能方面是,传入compile函数的元素和属性以原始html模板呈现。只会被运行一次,接下来会直接使用。另外一个重要的点是prelink和postlink的区别。prelink从外向内执行。postlinks从内向外执行。prelink性能稍好一些,因为它不会产生第二次更新周期。但是这时子元素的DOM还未被创建。

11 DOM事件问题

Angular提供了很多预定义的DOM事件指令。ng-click,ng-mouseenter,ng-mouseleave等等。当调用scole.$apply()时这些事件都会被执行。另外一种更有效率的方式是直接在DOM上面绑定addEventListener,并且尽量使用scope.$digest

优化实例

测试一个应用框架确实是个严峻的挑战,当用户点击日志中任何一个单词,我们就要搜索出相关信息,而页面上可以点击的元素又不计其数;我们想让日志的分页功能也瞬间得到反馈。我们其实已经预先获取到了下一页面的日志数据,所以用户接口的更新就成为了瓶颈,如果拿 AngularJS直接实现日志视图的换页功能需要1.2秒,但是如果仔细优化一下的话就可以降到35毫秒。这些优化被证明在应用的其他部分也是适用的,并且对AngularJS适应性也很好。但我们必须打破一些规则来实现我们的想法,稍后讨论。

一个Github更新的日志demo

An AngularJS log viewer

本质上,日志视图就是一个日志消息的列表,每个字都可以点击。所以把Angular的指令加到DOM元素中,简单实现如下:

rush:js;"> {{token | formatToken}}

在单页面应用中有个数千个tokens是很正常的,在早期的测试中,我们发现进入日志的下一页会花费好几秒来执行JavaScript。更糟的是,不相关的操作(比如点击导航下拉框)延迟也不轻,AngularJS的大神说最好把数据元素绑定的数量控制在200以下。对于一个单词就是一个元素的我们来说,早已远超这个数。

分析:

用Chrome的JavaScript profiler工具,我们可以快速定位两个拖延点。首先,每次更新要花大量时间在DOM元素的创建和销毁上,如果新的view有不同的行数,或者任何一行有不同数量单词,Angular的ng-repeat指令就会创建或者销毁DOM元素,这个代价太大了。

其次,每一个单词都有自己的change watcher,AngularJS会watch这些单词,一旦鼠标点击就会触发,这个是影响不相关操作(下拉菜单导航)延迟的罪魁祸首。

优化#1:缓存DOM elements

我们创建了一个ng-repeat指令的变体,在我们的版本中,如果绑定数据的数量减少了,超出的DOM元素会隐藏而不是销毁,如果元素的数量过会儿有增加了,我们会重用这些缓存的元素。

优化#2:Aggregate watchers

用来调用change watchers的所有时间大部分都浪费了,在我们的应用中,特定单词上的数据绑定都是永远不会改变的除非整个日志消息变化,为了达成这一点,我们创建了一个指令”hides“隐藏掉了子元素的change watchers,只有等特定父元素表达式修改的时候才会调用他们。就这样,我们避免了在每一次鼠标点击或者其他微小的修改而导致的全盘change watchers(为了实现这个想法,我们稍微修改了AngularJS的抽象层,我们稍后再细说)。

优化#3:推迟元素创建

前面说了,我们为日志里的每一个单词单独创建了DOM,我们可以利用每一行的单个DOM元素得到相同的视觉呈现;其他元素都是为响应鼠标点操作而创建的,因此,我们决定推迟这部分创建,只有当鼠标移动到某行的时候我们再创建他。

为了实现这个,我们为每一行创建了两个版本,一个就是简单的文本元素来显示完整的日志信息,另外一行就是个占位符,用来显示最终为每一个单词填充后的效果。这个占位符开始是隐藏的,当鼠标移动到那一行的时候才会显示,而简单文本那一行这个时候就隐藏掉。下面会讲到,显示占位符是如何填充单词元素的。

优化#4:避开对隐藏元素的监视

我们创建了另外一个指令,用来阻止对隐藏元素的监视,这个指令支持优化#1,相较于原数据,我们多了更多的隐藏DOM节点,所以必须消除对多出来的DOM节点的监视。这也支持优化#3,让推迟单词节点的创建更加容易。因为直到这行数据的tokenized版本出现我们才会创建他 。

下面的代码就是所有的优化后的样子,我们自定义的指令是粗体显示。

rush:js;">
{{logLine | formatLine }}
{{token | formatToken }}

Sly-repeat 是ng-repeat的变体,用来隐藏多出来的DOM元素而不是销毁他们,sly-evaluate-only-when阻止内部change watchers除非“logLines”变量修改,sly-prevent-evaluation-when-hidden主要负责当鼠标移动到指定行的上面的时候,隐藏的div才显示。

这里展示出了AngularJS对于封装和分离的控制力,我们做了复杂的优化但是并没有影响模板的结构(这里展示的代码并不是真正产品里的代码,但是他展示了所有的要点)。

结果:

我们来看一下效果,我们添加了一些代码来衡量,从鼠标点击开始,一直到Angular's $digest循环结束(意味着更新DOM结束)。

我们衡量点击”下一页“按钮的性能是通过Tomcat日志,环境用的是MacBook Pro上的Chrome,结果见下表(每个数据都是10次测试的平均值):

获取数据 这些数据不包括浏览器用在DOM布局和重绘(JavaScript执行完成后)的时间,每次大概30毫秒。尽管如此,效果也显而易见;下一页的响应时间从1200毫秒骤降至35毫秒(如果算上渲染是65毫秒)。

“从服务器获取数据”里的数据包括了我们使用AJAX从后端获取log数据的时间。这个跟点击下一页按钮不同,因为我们预取下一页的log数据,但是或许适用于其他的UI响应。即使这样,优化后的程序也可以做到实时更新。

总结

以上是小编为你收集整理的整理AngularJS框架使用过程当中的一些性能优化要点全部内容。

如果觉得小编网站内容还不错,欢迎将小编网站推荐给好友。

性能性能

JavaScript相关文章

2022最全最新前端面试题(附加解答)
这是我整理所有看过的文章的面试题+各种百度每一道题的答案,希望可以有效的帮助别人本章博客,梳理所有基础的js,jquery,vue,css, html等题,包含面试题,可供参考学习,也督促自我学习
前端面试八股文(详细版)—上
前端面试八股文,知识点广而全,内容会及时更新
Js运算符
JavaScript 语言的算术运算符是使用数字值作为操作数,进行运算之后返回一个数字值。算术运算符+,-,*,/,%% => 模(余数)
【Vue】webpack的基本使用
好处:前端开发自成体系,有一套标准的开发方案和流量。概念: webpack是前端项目工程化的具体解决方案。主要功能:它提供了友好的前端模块化开发支持,以及代码压缩混淆,处理浏览器端JavaScript的兼容性性能优化等强大的功能。好处:让程序员把工作的重心放到具体功能的实现上,提高了前端开发效率和项目的可维护性。注意:目前Vue,React等前端项目,基本上都是基于webpack进行工程化开发的。步骤import和require导入模块的区别1、require对应导出的方法是module.export
Pro3:js实现放大镜效果
JavaScript练习项目第三个:js实现放大镜的效果。
【2022-11-26】JS逆向之北京百姓网
北京百姓网cookie逆向
你评论,我赠书~【TFS-CLUB社区 第9期赠书活动】〖HTML5+CSS3+JavaScript从入门到精通(微课精编版)(第2版)〗等你来拿
你评论,我赠书~【TFS-CLUB社区 第9期赠书活动】〖HTML5+CSS3+JavaScript从入门到精通(微课精编版)〗等你来拿
App逆向案例 X嘟牛 - Frida监听 & WT-JS工具还原(一)
App逆向 X嘟牛 - Frida监听 & WT-JS工具还原(一)
  • • 2022最全最新前端面试题(附加解答)
  • • 前端面试八股文(详细版)—上
  • • Js运算符
  • • 【Vue】webpack的基本使用
  • • Pro3:js实现放大镜效果
  • • 【2022-11-26】JS逆向之北京百姓网
  • • 你评论,我赠书~【TFS-CLUB社区 第9期赠
  • • App逆向案例 X嘟牛 - Frida监听 &
  • • js中的正则表达式入门
  • • JavaScript箭头函数中的this详解
HTMLreactjsCSSNode.jsangulartypescriptvue.jsreact-natispringkotlinAPIseleniumtensorflowbashangularJSexpressxcodematplotlibflaskHibernatedictionaryrailscocoswebnpmreact-hookmongoosegoogle-appformswpfRestwebpackunit-testihttpclassfileNext.jsJsHTML5bootstrap-
  • 友情链接:
  • 菜鸟教程
  • 前端之家
  • 编程小课
  • 小编
  • -
  • 我要投稿
  • -
  • 广告合作
  • -
  • 联系我们
  • -
  • 免责声明
  • -
  • 网站地图
版权所有 © 2018 小编 闽ICP备13020303号-8
微信公众号搜索 “ 程序精选 ” ,选择关注!
微信公众号搜"程序精选"关注
微信扫一扫可直接关注哦!

Angular 14 inject 函数使用过程中的一些注意事项

Angular 14 inject 函数使用过程中的一些注意事项

inject 函数只能用于构造器阶段,这意味着其只能在构造器函数作用域(constructor function scope)和字段初始化器(field initializers)中使用。

下列代码会遇到运行时错误(runtime error):

因为使用到了 inject 函数的 fetchEntity 方法,在构造函数作用域之外的上下文里被调用,不符合 inject 函数的使用前提。

当在构造函数阶段之外调用 refreshEntity 方法时,上面的代码将引发运行时错误,例如在单击按钮时,因为 fetchEntity 使用了 inject()。 当用于初始化 entity$ 属性时,它不会抛出此错误,因为它处于构造函数阶段。

解决方案也不难,使用 JavaScript 的 closure 闭包概念:

在上面的例子中,因为我们使用了一个闭包,所以我们能够将注入的 HttpClient 和 ActivatedRoute 存储在闭包范围内,并且仍然使用返回函数中的值。因此,我们可以在构造函数阶段之外利用 inject() 函数。

正如我们在上面的示例中已经看到的那样,使用 inject 函数能够保持组件符合单一职责的设计准则(single responsibility)和无依赖注入。

依赖注入或 DI 是 Angular 中的基本概念之一。 DI 被连接到 Angular 框架中,并允许具有 Angular 装饰器的类(例如组件、指令、管道和可注入)配置它们需要的依赖项。

DI 系统中存在两个主要角色:依赖消费者和依赖提供者。

我们不再直接在组件构造函数中依赖 HttpClient 或 ActivatedRoute。 相反,我们创建了一个可注入的函数来处理业务逻辑,这种思路类似于我们如何将逻辑提取到一个 Facade 服务中。并且 Angular 的最佳事件认为,Component 需要完成的业务逻辑最好都封装到一个专门的 Facade 服务中。
使用 inject() 函数,我们不再需要组件中的任何依赖项。

angular 单元测试过程当中错误类型总结

angular 单元测试过程当中错误类型总结

1错误类型

Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.

测试代码

Auth.currentStaff().then(function(data) {
                currentStaff = data;

            });

错误原因:异步回调函数导致执行过程当中不能及时获取到相应的测试数据

解决方案:给代码中加入

$rootScope.$apply();//$rootScope.$digest();

angularjs – Angular.js 1.3 ng-bind中的一次性绑定

angularjs – Angular.js 1.3 ng-bind中的一次性绑定

在Angular.js 1.3我可以做一次绑定:
{{::name}}

但是如何在ng-bind中使用呢?

ng-bind与{{语法}相比有一些性能改进。

是否支持?

是。这工作:
<span ng-bind="::name"></span>

angularjs – 在Angular 1中是否存在单向绑定的性能优势

angularjs – 在Angular 1中是否存在单向绑定的性能优势

在阅读angular.component风格的单向绑定时,我遇到了多个语句< vs =产生较少的观察者(=将有额外的观察者来传播从孩子到父母的价值变化). 但是我刚创建了一个虚拟组件,通过=和<和观察者的数量是一样的. 因此严格地说性能:<之间是否存在差异?和=?

解决方法

我带着同样的问题来到这里,对于没有回答感到失望……
我有一个小的测试应用程序,我使用各种绑定,其中三个是单向的.我观察了手表的数量(使用 ng-stats utility),得到了42.
我改变了这些“<”到“=”,这当然改变了我的应用程序的行为. ng-stats仍然报道了42只手表.
所以,至少就手表而言,这并没有带来性能提升.

我想这里更方便,避免不必要的副作用(孩子改变一个值,父母的价值被不情愿地改变)和促进良好实践(使用绑定功能代替手表,如下所述).

它仍然可以成为一种避免手表的方法:当父母想要被告知孩子的变化时,通常的做法是使用双向绑定,设置监视值,并对变化作出反应.另一种方法是设置单向绑定(以提供子进程),并提供回调(通过“&”绑定),从而让子进程通过此回调通知更改.它更主动,它删除了一块手表.

今天关于整理AngularJS框架使用过程当中的一些性能优化要点angularjs框架怎么搭的介绍到此结束,谢谢您的阅读,有关Angular 14 inject 函数使用过程中的一些注意事项、angular 单元测试过程当中错误类型总结、angularjs – Angular.js 1.3 ng-bind中的一次性绑定、angularjs – 在Angular 1中是否存在单向绑定的性能优势等更多相关知识的信息可以在本站进行查询。

本文标签: