項目中Angularjs遇到的問題和最佳化總結__js

來源:互聯網
上載者:User
項目中Angularjs遇到的問題和最佳化總結

由於本項目最低需要相容ie8瀏覽器,所以在版本選擇上選擇Angularjs1.2版本。 1.ng-if/ng-switch與ng-show/ng-hide區別選擇 ng-show/ng-hide是通過修改CSS樣式方式控制元素顯示與隱藏,對應的DOM元素會一直存在於當前頁面中,本質是CSS屬性操作display:none;display:block,而ng-if根據運算式的值動態在當前的頁面中添加刪除頁面元素。如果賦值運算式的值為false,那麼這個元素就會從頁面中刪除,否則會添加一個元素。ng-if建立元素時用的是被它編譯後的代碼,如果ng-if內部的代碼被其它方式修改過,那麼修改只會對本次展現有效,頁面元素重新渲染後修改效果會消失,而ng-show/ng-hide則能夠保留dom元素上次修改後的狀態。 在範圍方面,兩者也存在差異:當一個元素被ng-if從DOM中刪除時,與其關聯的範圍也會被銷毀。而且當它重新加入DOM中時,則會產生一個新的範圍,而ng-show和ng-hide則不會。

項目中由於需要多個列表資料較多,如果頻繁的重建和刪除DOM元素,將十分耗效能,所以在效能考慮上使用ng-show。

當然也有另一種情況,那就是一些長列表資料,可能有一些東西是通過預設隱藏,點擊顯示的形式展現的.而這部分可控制顯隱的內容中也會伴隨很多資料繫結.這個在頁面渲染的時候非常影響效能.(angular建議一個頁面的資料繫結不超過2000個,假如現在有一個頁面直接綁定了2000個model,然後你載入,會發現非常卡.如果你將每100的model設定為ng-show,預設情況下不顯示,你會發現還是很卡.)然後你將所有的ng-show換成ng-if,你會發現效能瞬間快的像兩個應用.原因在ng-show還是會執行其中的所有綁定,ng-if則會在等於true,也就是顯示的時候再去執行其中的綁定.這樣一來效能就有很大的提高.




ng-show = false


ng-show=true


ng-if = true


ng-if = false



angular.module(“app”,[]).controller(“MainCtrl”,function($scope){
});

樣本demo 2 雙向資料繫結{{}}使用重新整理出現{{}}

由於後台資料問題沒有訪問成功,前台介面就不需要顯示{{}},用ng-bind指令代替{{}} 3 rootScrope以及和 rootScrope以及和scope的區別。 rootScrope頁面所有 rootScrope 頁面所有scope的父親。 如何產生 rootScope和 rootScope和scope

step1:Angular解析ng-app然後在記憶體中建立$rootScope。

step2:angular回繼續解析,找到{{}}運算式或者ng-bind指令,並解析成變數。

step3:接著會解析帶有ng-controller的div然後指向到某個controller函數。這個時候在這個controller函數變成一個$scope對象執行個體。 4 使用路由 去除url中總是預設帶有”#”

在設定route的時候,開啟HTML5模式.

angular.module('router', ['ngRoute']).config(['$routeProvider', '$locationProvider',  function($routeProvider, $locationProvider) {    $locationProvider.html5Mode(true);   // 設定一下這句即可  }]);
5 頁面快速定位元素位置

一般來講頁面內通過這樣的形式就可以結合js代碼,實現快速定位.在angular中也是通過類似的原理實現,代碼如下:

var old = $location.hash();$location.hash('batchmenu-bottom');$anchorScroll();$location.hash(old);

這樣寫是因為直接location.hash會導致url變化,頁面跳轉,所以加了防止跳轉的代碼. 6 使用路由切換不同模組需要全顯示 在使用路由開發時,切換路由將會重新remove上一個模組的div,重新添加下個模板。一般項目中可能都會有需求需要固定頭部header和sidebar,這樣不同模板之間切換每次變化的都是ui-route(原生ngRoute)內的ui-view(ng-view)的template。如果有一個頁面需要瀏覽器顯示整個完整的頁面,不包括頭部和側邊欄。 可以使用ng-if綁定變數控制頭部和側邊欄的顯示和隱藏。

1.可以直接在service中做一個全域變數進行控制

2.訊息廣播方式:具體變數的綁定可以在controller中通過 scope. scope.emit向上發送一個訊息,然後頁面的controller通過 scope. scope.on監聽訊息,一旦收到訊息,改變變數值。 7 ng-repeat的使用

項目中有個需求需要即時跟新列表資料list,按照傳統的做法是使用定時器每隔10000ms向後台發送請求,和原來資料對比,資料跟新後首先移除本來的列表div,然後重新動態添加新資料列表,一般不使用任何架構的情況下,都是用jquery進行操作,但是這裡有一個問題,就是即時資料量很大,就要不斷的dom的操作,而dom操作是十分消耗效能的。

考慮到以上問題,採用Angular內部服務 http進行後台資料請求,同時在控制器中使用 http進行後台資料請求,同時在控制器中使用scope.$watch()監聽資料的變化,和舊資料對比是否發生變化,然後使用內部指令ng-repeat便利數組產生Dom元素,進行列表顯示。

ng-repeat在使用過程中還要考慮一個效能問題,這個坑也要十分注意,不然對整體效能的提升作用不大。

為了方便說明,這裡舉一個小小例子。

<body ng-app="myApp" ng-controller="myCtrl">    <button ng-click="request()">重新請求新資料</button>    <ul>        <li ng-repeat="data in records">{{data.name}}</li>    </ul></body><script>var app = angular.module("myApp", []);app.controller("myCtrl", function($scope) {    var data1 = [];    var data2 = [];    for (var i = 0; i < 3; i++) {        data2[i] = data1[i] = {            id: i,            name: "jay: " + i        };    }    for (var i = 0; i < 3; i++) {        data2[i] = {            id: "id"+i,            name: "sum: " + i        };           }    $scope.records = data1;    $scope.request = function () {        // 模仿從伺服器載入新資料        var result = data2;        // 直接重新賦值給 records        $scope.records = result;    };});</script>

開始展示data1數組列表,點擊請求資料後重新向$scope.records中替換資料data2,data1和data2長度相同但是內容不同。重新請求資料,查看ng-repeat中源碼可以發現,當ng-repeat中的數組內容發生變化時,會將原來的dom刪除,根據新的資料重建新的dom元素。

    // remove existing items  for (key in lastBlockMap) {    // lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn    if (lastBlockMap.hasOwnProperty(key)) {      block = lastBlockMap[key];      elementsToRemove = getBlockElements(block.clone);      $animate.leave(elementsToRemove);      forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; });      block.scope.$destroy();    }  }

在代碼中進行斷點進入操作,發現即使使用了ng-repeat指令,還是對dom進行了頻繁的消除和重建操作,對效能的提升並沒有多大作用,我們不會想為什麼ng-repeat不能利用已經存在的dom元素去跟新新載入的資料,而不是頻繁的remove和create。

查看ng-repeat的使用API後發現,ng-repeat內有一個track by $index代碼。

<li ng-repeat="data in records track by $index">{{data.name}}</li>

加上這段代碼之後,重新重新整理回到我們的例子,發現點擊請求載入資料後,沒有進入上那段代碼之中了。這是為何呢。

刪除track by $index代碼,重新操作添加前demo,可以看到ng-repeat往數組裡的每個新添加的元素加了一個$$hashkey屬性,這個key是由Angualr內部的nextUid()方法產生,類似資料庫的自增id號,使用字串進行唯一標示。這下明白,為什麼dom不能重用,因為每次替換數組都會導致ng-repeat為每個元素產生一個新的key進行唯一標識,這樣就沒有辦法重用已有的dom元素。

當使用ng-repeat時要盡量避免對全域列表的重新整理。ng-repeat會產生一個$$hashkey屬性和一系統唯一的項。這意味著當你調用 scope.listBoundToNgRepeat = serverFetch() 時會引起對整個列表的重新重新整理。會通知執行所有的watchers並觸發每一個元素,這是非常消耗效能的。這裡有兩種解決方案。一種是維護兩個集合,和帶有過慮器(filter)的ng-repeat(基本上需要自訂同步邏輯,因此演算法更複雜,可維護性更差),另一種方案是使用track by去指定你自己的key(Angular 1.2 開始支援,只需要很少的同步邏輯)。

添加track by $index後,重新查看,發現新添加的數組中沒有出現$$hashkey屬性,這樣ng-repeat就可以將其緩衝起來,僅僅對dom中的資料進行替換操作,從而提升效能。

同時我們查看dom樹的跟新狀態也能看出是重新建立了dom,還是只是對資料進行了替換。

8.使用雙向資料繫結搭建多級聯動操作

雙向資料繫結搭建多級聯動操作
9關於ui-router記憶體泄露問題的github上討論

路由記憶體泄露問題

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.