码迷,mamicode.com
首页 > Web开发 > 详细

AngularJS--不能回避的4个问题

时间:2015-08-12 23:17:03      阅读:314      评论:0      收藏:0      [点我收藏+]

标签:

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框架在初始化加载时,耗时成本会更高,影响用户体验。

技术分享

 


 

三、数据绑定性能瓶颈

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>

 

技术分享

 

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

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

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

技术分享

 

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

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

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

 

技术分享

 

技术分享

 

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

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

 

技术分享

 

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

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

技术分享

 

<!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错乱。

技术分享

 


 

四、移动应用尴尬

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。

 

 

AngularJS--不能回避的4个问题

标签:

原文地址:http://www.cnblogs.com/tgor/p/4725615.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!