深入探索AngularJS


數據雙向綁定並不是Angular最出彩的地方。大部分對AngularJs的介紹都偏重於使用,使用的學習只是學了AngularJs的API,而那只能AngularJs的很小一部分。隨着使用越來越深,系統越來越大,我們也越來越迷失,是時候深入AngularJs的實現來學習。因為AngularJs 2.0就要來了,由於2.0和1不兼容,基於API的學習不再有用,而內部實現的精華才能延續。其實,軟件的很多技術也大都如此,沖走的是實現,留下的是思想。

原文

深入探索AngularJS

作用域Scope是DOM和Directives交互的抽象

Scope是POJO對象

AngularJS只是往Scope中添加了很多“內部"屬性,大部分以$開頭,還有些以$$開頭,兩個$開頭的屬性一般不要使用。

Scope是上下文

應該看作是一個容器,保存着當前的上下文和上下文敏感的變量數據等

Scope繼承樹

  • Scope總是和一個DOM元素聯系起來
  • Controller會創建一個新的Scope
  • Directive有時候會創建一個新的Scope
  • 其他情況會直接使用父級的Scope
  • 如果不在ng-app內,沒有任何相關的Scope

Scope附加功能

AngularJS往Scope中添加了一些屬性

遍歷功能

  • $id
    Scope的唯一id號
  • $root
  • $parent
  • $$childHead
  • $$childTail
  • $$prevSibling
  • $$nextSibling

正交功能

Element和Attribute

Directive可以定義為Element(標識)也可以定義為標識的屬性。 更為強大的架構就是綜合應用這兩種功能,用屬性定義來改變或增強原Element的功能。

模塊模式 - Module Pattern

模塊模式是一個設計模式,它能夠消除大量重復的 thisprototype使用。 Angular Material就使用這個模式開發模塊代碼 Angular Material Coding Conventions and Guidelines
參考: http://toddmotto.com/mastering-the-module-pattern/

創建模塊

(function(){
	//code
})();

這里申明了一個函數,然后馬上調用它自己,這也被稱作立即執行函數表達式 (Immediately-Invoked Function Expression)。這個函數就創建了一個新的作用域(Scope),從而模擬了類似私有域的效果, 把大部分代碼從全局作用域(Gloable Scope)中隔離出來。

創建新的作用域之后,我們需要把代碼賦於命名空間。

var Module = ( function () {
	//code
})();

這樣,我們就在全局作用域中申明了 Module,這樣我們就可以任意調用它,甚至把它傳給另外一個模塊。

私有方法 - Private Method

Javascript所有的函數定義默認下都是全局的,而且Javascript也沒有命名空間的概念,這兩個缺陷使得Javascript很容易產生名稱沖突。 模塊模式可以幫助解決這些問題。

Javascript 本身不能夠定義私有方法,但是我們可以使用模塊模式模擬出私有方法的效果。

私有方法本質上是:你不希望外部用戶調用執行的某個作用域內部的任何東西。特別是那些從服務器讀取或回寫的操作。

通過模塊模式,我們可以如下隱藏私有方法:

var Module = (function(){
	var privateMethod = function(){
		//do something
	};
})();

在新作用域內部申明的方法privateMethod就很好的隱藏起來,任何外部試圖調用privateMethod都會導致錯誤。

理解返回 - Return

景點模塊模式可以用 return返回一個對象給模塊,那些在該對象下聲明的方法可以通過模塊的命名空間來調用。

var Module = (function(){
	return {
		publicMethod:function(){
			//code
		}
	};
})();

調用: Module.publicMethod();
這和標准方式定義的對象沒有任何區別:

var myObj = {
	defaults: { name: 'Hao Wang'},
	publicMethod: function () {
		console.log(this.defaults);
	}
};

//調用
myObj.publicMethod();

當時標准方式的問題是,一些內部屬性和方法都暴露出來了,不能隱藏(Javascript沒有私有屬性和方法)。 如上面例子中的defaults就有可能被外部用戶修改,導致不期望的行為。

Promise - 異步的承諾

Promise讓異步調用看起來更像同步調用,從而很容易的取到返回值和捕獲異常。

介紹

使用Promise我們可以在任何一個執行點捕獲錯誤,然后忽略剩下的執行步驟。 這種流程控制來源於新的代碼風格本身,無需額外的代碼。 從而,我們可以很容易的組合多個函數功能並且異常以冒泡式的拋出,同時有維持異步運行的能力。

Promise自始自終都是異步運行,我們不用擔心它會阻塞其它部分的代碼運行。

Promise in Angular

Angular的事件循環(Event Loop)在$rootScope.$evalAsync階段解析(Resolve)Promise,直到$digest運行循環結束。 我們和容易的把Promise的結果輸出成視圖,這能夠直接把XHR調用的結果直接賦給$scope對象的一個屬性。

使用Promise到后台取數據的一個實例

<ul ng-controller="DashboardController"> 
	<li ng-repeat="pr in pullRequests">
		{{pr.title}}
	</li>
</ul>

當用服務返回一個promise, 我們可以用.then()方法與promise進行交互操作, 我們可在該方法中修改scope中的任何變量,從而改變視圖。

angular.module('myApp', [])
  .controller('DashboardController', ['$scope', 'GithubService', function($scope, GithubService){
    GithubService.getPullRequests(123)  //這里返回的是Promise
      .then(tunction(data){
        $scope.pullRequests = data.data;
      });
  }]);

創建一個Promise

內建服務$q可以用來創建你自己的Promise。我們可以通過調用$q.defer()方法來創建一個“延遲”對象: var deferred = $q.defer();
“延遲”對象有三個方法和一個promise屬性,該屬性返回一個Promise對象。

  • .resolve(value) - 解析(返回結果)方法
  • .reject(reason) - 拒絕方法;等同於解析出一個拒絕對象.resolve($q.reject(reason));
  • .notify(value) - 返回執行的狀態方法

Promise執行狀態

如果我們有一個長時間運行的請求,可以調用.notify()來及時返回進程狀態。 通常,我們會把這個長時間任務放在一個服務中:

.factory('GithubService', funcion($q, $http){
  var getEventsFromRepo= function(){
    //task
  };
  var service = {
    makeMultipleRequests: function(repos){
      for (var i=0; i < repos.length; i++) {
        output.push(getEventsFromRepo(repos[i]));
        percentComplete = (i+1) / repos.length * 100;
        d.notify(percentComplete);
      }
      d.resolve(output);
      return d.promise;
    }
  }
  return service;
}); 

這里,每取一個repo, 我們就會收到一個進程狀態的通知。下面是對這個Pomise的使用和狀態通知的顯示

.controller('HomeController', function($scope, GithubService){
  GithubService.makeMultipleRequests(['auser/behavior','..'])
    .then(function(result){
      //Handle the result
    }, function(err){
      //Error occurred
    }, function(percentComplete) {
      $scope.progress=percentComplte;
  	});
});

異步流

Promise的then()方法返回一個新的Promise, 這個新的Promise實際上是在原始Promise的值解析之后創建的。這樣我們就可以用then()讓異步的執行通過一個一個Promise串聯下去。

使用then()我們創建了異步執行體流,這樣我們可以在任何一步切入,然后切換不同的返回值。 這種切換也可以染我們暫停或者延遲解析的流程。

$http服務就是使用這種切入來實現請求和響應的interceptors。

$q服務還有幾個其他的幫助方法:

  • $q.all(promises) - 可以把多個Promise合並成一個Promise。
  • $q.defer() - 創建一個延遲對象。
  • $q.reject(reason) - 創建一個Promise,其解析值為rejection
  • $q.when(value) - 把一個對象封裝成為Promise,這個對象可以是普通對象也可以原本就是Promise。

與服務器的交互

談到后端時,我們有兩種情況:有服務器后端和無服務器后端

ExpressJS作服務器后端

搭建Express

  1. 安裝NodeJS
  2. 安裝Express: $ npm install -g express-generator
  3. 創建網站: $ express myApp
  4. 運行App准備:` cd myApp && npm install -d
  5. 運行App: `$ node app.js
  6. 高級運行App (源代碼的改動觸發重新編譯):
    $ npm install --save-dev node mon
    $ nodemon app.js

( 本文版權屬於© 2015 卓逸天成 | 轉載請注明作者和出處:卓逸知識文庫 )


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM