zoukankan      html  css  js  c++  java
  • AngularJS--不能回避的4个问题

    AngularJS是一个很容易让人上瘾且深陷其中的JS框架,它的MVC特性大大减少的Web开发难度,提高代码后期的维护性。学会了这个框架,有时候甚至开发个最简单的静态页,你也会情不自禁问问自己,可以用Angular吗?

    但事物都是有双面性的,简单说说那些AngularJS开发的。


     

    一、体积庞大

    AngularJS,核心模块加上route、cookies两个核心模块,压缩后min版本的体积大约120k,如果算上HTTP GZIP传输压缩的话,体积能缩减到60~70k左右那AngularJS的JS库体积真的大吗?对比想想jQuer框架压缩后也有100k,即使是同样的前端MVC、号称是精简到极致的Backbone,在加入几个依赖后的框架zepto or jQuery、underscore以后大小也达到了60~70k。这样想想,AngularJS真的不算大?

    这个问题在PC端是肯定的,但别忘了,我们还有千千万万的2G网络移动端的用户。也许目前在移动端广泛使用的框架,依然是以zepto为代表的轻量级jQuery框架,但在未来,AngularJS这个单页应用非常适合做WebApp的框架真的为移动端Web带来更多更出色的体验。


    二、初始化成本高,耗时长

    与后端静态化页面(后端MVC框架)理念不一样,像.net的Razor、java的freemarker,后端处理好动态数据,并生成静态页面,浏览器接收资源仅负责渲染。

    而AngularJS(前端MVC),浏览器接收到的仅是没处理HTML(可以理解就是模板),一边渲染,一边加载Angular.js文件;然后Angular初始化,设定事件

    监听,并进入HTML结构找寻到带有{{ xxx }}、ng-xxx的标识,绑定动态数据,浏览器重新渲染。

    因此,不可避免的是,前端MVC框架在初始化加载时,耗时成本会更高,影响用户体验。

    Image2_thumb21

     


    三、数据绑定性能瓶颈

    Angular双向数据绑定、作用域、指令的性能瓶颈是我们在日常开发过程中要谨慎处理的。了解了其实现原理,也明白,这块的性能瓶颈是不可避免。

    举一个最简单的例子,作用域下name对象,输入框修改name对象值,h1同步刷新{{name}}。

    <!DOCTYPE html>
    <html ng-app>
    <head>
        <title>Simple app</title>
    </head>
    <body>
        <input ng-model="name" type="text" placeholder="Your name">
        <h1>Hello {{ name }}</h1>
        <script src="http://cdn.bootcss.com/angular.js/1.2.19/angular.js"></script>
    </body>
    </html>

    Image_thumb3

    代码很简单,一句JS代码都没有,就完成了将输入框输入值同步显示的效果。Angular如何实现?首先,Angular在初始化阶段时,做了两件事情:

    1)、注册监听所有会改变作用域的事件,可以是指令(内置及自定义指令)、Form输入事件、地址变更、Ajax等等动作。如上例子就是,text input的键入事件;

    看到on function是不是有种似曾相识的感觉,是的,就是类似jQuery的on绑定函数。

    Image1_thumb1

    2)、创建作用域,建立DOM与作用域的映射,并在作用域Scope对象中创建$watch监听属性,$watch中会记录Scope最近两个值。

    当触发监听事件时,Angular会带着域中新修改的对象值(脏值),进入到脏值循环的函数中$digest(),脏值循环函数会从根作用域$rootScope开始,

    类似二叉树的运作模式,遍历根的所有子节点作用域$scope,取出每个作用域scope的watch最近两个值,然后比较是否发生变化,变化的话就重绘浏览器DOM。

     

    Image2_thumb2

     

    Image3_thumb2

    显而易见,每次的赋值改变都会引发脏值循环,脏值循环会引起整个树状结构的刷新,不可避免产生一定性能问题。但是,Google那帮大神毕竟是大神啊,整个树干刷新这种蠢事他们是不会干的。

    脏值循环是,从哪个节点作用域引发的改变就从哪个节点终止。如下图,假定D节点绑定的值发生改变,脏值循环会进入A B E C D,但是F不会。当然,如果是A发生改变,整个树干都会刷新。

     

    Image_thumb5

    结论是:值域绑定数量,就是整个树干的所有级别的所有节点数量应该控制在2000以下。我想,应该足够了吧。

    参考以下例子Test1,应该能够说明问题,当$scope.lis循环值达到2000时,改变number值,整个页面会出现明显卡顿。

    Image_thumb7

    <!DOCTYPE html>
    <html ng-app="newApp">
    <head>
        <!--<meta name='viewport' content='width=device-width,minimum-scale=1.0 maximum-scale=1.0 user-scalable=no'>-->
        <title>Simple app</title>
        <style>
            body {
                font-size: 30px;
            }
    
            ul {
                margin: 0;
            }
    
            .error {
                background-color: red;
            }
    
            .level {
                padding: 20px;
            }
    
                .level.level-root {
                    background-color: #f2f2f2;
                }
    
                .level.level-1 {
                    background-color: #c7e2f1;
                }
    
                .level.level-2 {
                    background-color: #edc79e;
                }
        </style>
    </head>
    <body>
        <div ng-controller="FirstController" class="level level-root">
            <div class="level level-1">
                {{number}}
                <input ng-model="number" value="{{number}}" />
                <button type="button" ng-click="print()">print</button>
                <ul ng-repeat="n in lis" class="level level-2">
                    <li>
                        <div>
                            {{number}}/{{n}}
                            <input ng-model="number" value="{{number}}" />
                            <button type="button" ng-click="print()">print</button>
                            <button type="button" ng-click="change(n)">change</button>
                        </div>
                    </li>
                </ul>
            </div>
        </div>
        <script src="http://cdn.bootcss.com/angular.js/1.2.19/angular.js"></script>
        <script>
            var app = angular.module('newApp', []);
    
            app.controller('FirstController', ["$scope", "$http", function ($scope, $http) {
                $scope.number = 1;
                $scope.lis = [];
                for (var i = 1; i <= 2000; i++) {
                    $scope.lis.push(i);
                }
    
                $scope.print = function () {
                    console.log($scope.number);
                };
                $scope.change = function (n) {
                    n = 5;
                };
            }]);
        </script>
    </body>
    </html>

    ps,有个要注意地方是:循环绑定值域只能向子级传递,不能逆向父级传递。

    如下图节点2修改number值为1234,number不能向上父级传递,导致全局number错乱。

    Image_thumb10


    四、移动应用尴尬

    angular.js是核心模块,但不支持移动触摸应用,ng-click依然采用原生click事件,会有200ms延迟。注入angular-touch模块,在移动应用中,angular会自动将ng-click指令的click事件转为tap,并扩展swipe滑动支持。

    但之所以说这块还不成熟是因为,目前很多增强触摸滑动体验的js库(iscroll、islider……),都是以拆分滑动事件区分处理为设计准则的。最简单的例子,向左滑动:islider会区分处理触摸前触碰瞬间的事件touchstart、拖动手指的事件touchmove、手指离开屏幕的事件touchend;然而,angular touch就给你提供一个动作,就是向左滑动,然后,没有然后了。

    虽然说,各自运作问题不大,但如果要在angular项目中加入这些js库,到了数据绑定、DOM处理这些环节的时候,会出现很多不可预知的bug。

     

  • 相关阅读:
    罗美琪和春波特的故事...
    欢迎参与 KubeVela 官方文档翻译活动
    开源 1 年半 star 破 1.2 万的 Dapr 是如何在阿里落地的?
    Service Mesh 从“趋势”走向“无聊”
    Nacos 2.0 性能提升十倍,贡献者 80% 以上来自阿里之外
    阿里巴巴云原生 etcd 服务集群管控优化实践
    KubeVela 1.0 :开启可编程式应用平台的未来
    知行动手实验室可以用来做什么?
    7. Jackson用树模型处理JSON是必备技能,不信你看
    Linux:sudo,没有找到有效的 sudoers 资源
  • 原文地址:https://www.cnblogs.com/tgor/p/4725615.html
Copyright © 2011-2022 走看看