七、Angular.js 中的承诺

在上一章中,我们学习了 Node.js 及其实现。 我们还看到了 Node.js 如何被用来放大实时网络,以及如何利用承诺来交付更高效的应用。

在本章中,我们将研究承诺实现的另一方面,即 Angular.js 中的承诺。

随着我们的学习,我们将了解什么是 Angular.js,为什么要创建它,它会给我们带来什么好处,最后,承诺是如何在 Angular.js 中实现的。

让我们开始介绍 Angular.js 以及如何设置它。 本文将提供一些示例代码和工作示例。 然后我们将转向 Angular.js 中的承诺。

Angular.js 的演变

自从单页 web 应用诞生以来,人们已经有了许多为此类应用编写代码的方法。 单页网页应用的使用率一直在迅速增长,因为它们速度更快,平台独立,适用于所有类型的设备,并且可以自动调整到所有屏幕尺寸。 这就是为什么工程师们想要开发单页 web 应用,并且更喜欢使用库和框架来简化他们的日常工作的主要原因。

Angular.js 的初始概念也是相同的。 Angular.js 的核心在于它采用了声明式编程概念,即用户界面应该用于连接软件服务,而我们可以使用命令式编程来定义业务逻辑。

Angular.js 的框架扩展了经典的 HTML (HTML5),将内容耦合在一起。 它使用了双向数据绑定技术,这有助于模型和视图的自动同步。 有了这些特性,Angular.js 独立于 DOM,这有助于提高耦合模块的性能和安全标准。

Angular.js 最引人注目的非功能性属性是维护它的大脑——google。

谷歌是 Angular.js 不同版本的开发、维护和发布背后的力量。

Angular.js 于 2009 年首次发布,目的是提供客户端MVC(模型视图控制器)实现,从而简化应用的开发和测试。 此外,它还提供了一个嵌入式工具集,用于创建富 Internet 应用和现代实时 web 应用的工具。

The evolution of Angular.js

Angular.js 文档的结构

Angular.js 使用基本文档中的 HTML 文件来实现它。 它的语法非常简单,易于记忆。 页面的结构是一个简单的 HTML 文件,以ng开头。 这被称为 Angular.js 指令,它可以和 HTML 一起使用,也可以作为单独的文档链接。

要开始使用 Angular.js,你需要添加几行代码,它就会启动并运行。 要使用 Angular.js,请执行以下步骤:

  1. 添加ng指令; 你只需要添加以下简单的代码就可以开始使用 Angular.js 了:
  2. 将库添加到文件:
  3. 现在,像这样在 HTML 标签中定义变量:
  4. 最后,您可以通过调用变量

    <td> {{reservations.id}} < /td>

    来使用它:

开始使用 Angular.js

下载 Angular.js,请进入https://angularjs.org/,点击下载按钮。 将出现以下对话框:

Getting started with Angular.js

选择稳定的迷你版,点击下载。 这个文件是一个精简的,删除了所有的空白,以便它加载更快。 您需要将此文件保存到您的工作目录中,因为您将在本章的以下章节中需要它。

创建第一个 Angular.js 文件

我们将使用下载的文件包括在我们的 HTML。 从这里开始,它将展示 Angular.js 是一个双向带状框架的神奇之处,并实时显示结果。

步骤 1 -创建 HTML 5 文档

像这样创建文件:

<html>
<head>
  <title></title>
</head>
<body>

</body>
</html>

步骤 2 -添加 JavaScript 文件到它

使用以下代码创建 JavaScript 文件:

<html>
<head>
  <title> OPD System</title>
  <script type="text/javascript" src='angular.min.js' ></script>
</head>
<body> </body>

在前面的代码中添加 Angular.js 指令:

<html ng-app >
<head>
  <title>OPD System</title>
  <script type="text/javascript" src='angular.min.js' ></script>
</head>
<body>
</body>

这是它; 现在你就有了一个可以继续使用的 Angular.js 文件。

How to use Angular.js on your local machine

有几种方法可以在本地机器上对 Angular.js 进行采样。 一种方法是使用本地安装的服务器。 XAMPP 或 Node.js 服务器可能是执行 Angular.js 代码的最佳选择。

您可以从https://www.apachefriends.org/download.html下载 XAMPP 服务器并安装在您的 PC 上。 安装完成后,你可以把你的 Angular.js 文件/文件夹放到htdocs文件夹中,然后通过http://localhost/source/访问这些文件,source应该是htdocs里面的文件夹名。

使用 Node.js,简单地粘贴以下代码到一个文本文件,并将其保存为app.js:

//sample node server from official site at https://nodejs.org/
var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');

将此文件保存到驱动器上的任意文件夹。 现在,在 Windows 机器的Run工具中输入cmd,打开命令提示符,进入app.js所在的文件夹。

一旦你到达那里,请输入以下行,并按输入:

> node app.js

你会在屏幕上看到这样的响应:

Server running at http://127.0.0.1:1337/

获得此响应后,服务器就可以使用了。 把你的 Angular.js 文件放到app.js文件所在的文件夹中,然后像这样用浏览器访问它:

http://127.0.0.1:1337/source/

这里,sourceapp.js所在的文件夹。

您喜欢哪种服务器?

你可以使用这些服务器中的任何一个,因为它们都是开源的,都对 Angular.js 有很好的适应性。 使用哪一个完全取决于你。 为了让您更容易理解,我选择了 Node.js,因为它非常方便,易于维护,具有更多的性能输出。

Angular.js 的关键元素

在讨论 Angular.js 中承诺是如何实现的之前,我们先来看看 Angular.js 中的关键元素以及它们是如何为我们工作的。

在本节中,你将学习 Angular.js 的关键元素。 获得的技能将在本章接下来的章节中使用。 然后你就可以在 Angular.js 中应用承诺的概念,并根据你的需要在 Angular.js 中编写你自己定制的承诺。

我们将讨论的最常见的元素是:

  • 提供数据范围
  • 滤波输出
  • 控制范围
  • 路由视图

提供范围数据

我们将使用前端 HTML、CSS 和 JavaScript 在浏览器中显示结果。 我们还将从http://getbootstrap.com/getting-started/#download中获得引导,以在代码中进行修饰:

  1. The folder structure must be as defined in the following image. To demonstrate how code works, we will be using the Node.js server. The folder name public needs to deploy at the folder where app.js is located. Once the server has started, navigate to http://127.0.0.1:3000 and you will see the app running there.

    Supplying scope data

  2. 我们将为地铁站的可用服务创建一个应用。 让我们称这个车站为斯特拉特福德,我们将从这里查看哪些地铁服务是可用的。

  3. js/controller文件夹中创建一个文件,命名为app.js。 下面是这个文件的样子:
  4. 现在,在公共文件夹的根目录创建一个 HTML 文件,将其命名为index.html,并添加以下代码:

现在,当你在浏览器上点击刷新,它会显示哪些服务离 Stratford 车站很远。 然而,这怎么可能呢?

在 HTML 文档的顶部,有一个ng指令,它将创建 Angular.js 应用,然后我们可以包含 JavaScript 文件; 一个来自 Angular.js 的迷你文件,另一个是我们创建的 JavaScript 文件,它提供了让 HTML 显示它的作用域。 这一切都是因为一个变量声明$scope

$scope负责绑定数据并在提供的范围内提供输出。 这有助于 Angular.js 保持其唯一性,以便在一个孤立的或定义的影响范围内执行计算,仅此而已!

过滤数据

有时,我们需要有一个特定的数据格式来显示应用中的数据。在 Angular.js 中,这很简单,只要简单地为元素提供一些操作符,我们想要过滤它。

用于此目的的操作器为管|。 一旦我们添加了管道符号,Angular.js 就知道我们想要过滤掉一些东西。 让我们来看看两个最重要的过滤器:

要在页面输出时将文本转换为大写,请考虑以下代码:

<html ng-app>
<head>
  <title>Services listing </title>
  <script type="text/javascript" src="js/lib/angular.min.js"></script>
  <script type="text/javascript" src="js/controllers/app.js"></script>
  <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
  <link rel="stylesheet" type="text/css" href="css/bootstrap-responsive.min.css">
</head>
<body>
  <div class="container" ng-controller="AppCtrl">
    <h1>Services from Stratford station</h1>
    <ul>
      <li ng-repeat="service in service">{{serviceName.code}}
       - {{serviceName.name | uppercase}}</li>
    </ul>

  </div>
</body>
</html>

过滤数据最有用的特性是将整个对象作为 JSON。 这不仅有助于调试模式,还可用于验证所提供的数据,以查看格式是否正确。

考虑以下代码,它不仅将数据过滤为 JSON 对象,而且在显示输出前对其进行验证:

<html ng-app>
<head>
  <title>Services listing </title>
  <script type="text/javascript" src="js/lib/angular.min.js"></script>
  <script type="text/javascript" src="js/controllers/app.js"></script>
  <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
  <link rel="stylesheet" type="text/css" href="css/bootstrap-responsive.min.css">
</head>
<body>
  <div class="container" ng-controller="AppCtrl">
    <h1>Services from Stratford station</h1>
    <ul>
      <li ng-repeat="service in service">{{serviceName.code}}
       - {{serviceName | json}}</li>
    </ul>

  </div>
</body>
</html>

这将以 JSON 形式返回整个 JavaScript 对象。 现在您可以验证数据或进入调试模式,通过亲自动手,挖掘 JavaScript 代码并添加alert()

控制范围

我们还可以为特定的流提供整个函数而不是单个变量; 这将帮助我们链接任何应用的不同部分没有太多麻烦。 考虑下面的 JavaScript 代码,它显示了我们如何将整个函数提供给特定的流:

function AppCtrl ($scope) {
  $scope.serviceName = {
    "CRTL": {
      "code": "CRTL",
      "name": "Central Line Service",
      "currentLocation": "Oxford Circus",

    },

    "JUBL": {
      "code": "JUBL",
      "name": "Jubblie Line Service",
      "currentLocation": "westham",

    },

    "DLR": {
      "code": "DLR",
      "name": "Docland Ligt railway",
      "currentLocation": " westham",

    },

  };

  $scope.curretStation = null;

  $scope.setAirport = function (code) {
    $scope.curretStation = $scope.service[code];
  };
}

在的最后三行中,我们添加了一个函数,它将在 HTML 输出中完全传递给调用ng指令。 HTML 代码看起来像这样:

<html ng-app>
<head>
  <title>Services listing </title>
  <script type="text/javascript" src="js/lib/angular.min.js"></script>
  <script type="text/javascript" src="js/controllers/app.js"></script>
  <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
  <link rel="stylesheet" type="text/css" href="css/bootstrap-responsive.min.css">
</head>
<body>
  <div class="container" ng-controller="AppCtrl">
    <h1>Services from Stratford station</h1>
    <ul>
      <li ng-repeat="Services in ServicesName">
        <a href="" ng-click="setAirport(Services.code)">{{Services.code}} - {{Services.code}}</a>
      </li>
    </ul>

    <p ng-show="currentStation">Current Services: {{currentStationname}}</p>
  </div>
</body>
</html>

注意,我们正在编写非常整洁的代码,只有很少的更新。 在body标签完成之前,我们可以在最后几行实现许多想要的更改; 你会注意到我们是如何使用 Angular.js 传递整个函数的。

路由视图

传统的网站由许多页面组成,通过href标签链接在一起。 他们的内容很难阅读,需要比以往更多的维护。 随着单页面 web 应用的出现,信息会立即出现在浏览器上,因为视图可以从一个链接路由到另一个链接,而无需重复点击服务器,或等待页面加载。

Routing views

在我们的示例中,我们将添加另一个文件作为模块,并将其放在 JS 文件夹的根目录下。 代码看起来像这样:

angular.module('services', [])
  .config(airlineRouter);

function airlineRouter ($routeProvider) {
  $routeProvider
    .when('/', {templateUrl: 'partials/destinations.html',
      controller: 'DestinationsCtrl'})
    .when('/Services/:airportCode', {
      templateUrl: 'partials/stations.html',
      controller: 'ServiceCtrl'
    })
    .when('/service', {
      template: '<h3>Flights</h3> {{Services | json}}',
      controller: 'FlightsCtrl'})
    .when('/reservations', {
      template: '<h3>Your Reservations</h3> {{Services | json}}',
      controller: 'ReservationsCtrl'});
}

这将在浏览器上动态地生成视图,而不需要访问服务器。 我们需要更多的文件来添加更多的动态性。 我们将添加 partials 文件夹,其中放置了另外两个文件servicesdestination

destination.html文件看起来像这样:

<div class="pull-left span6">
  <h3>All Destinations</h3>
  <ul>
    <li ng-repeat="destinationin destinations">
      <a href="" ng-click="setDestinations (service.code)">{{name.code}} - {{destination.name}}</a>
    </li>
  </ul>

</div>
<div class="span5" ng-include src="sidebarURL"></div>

services.html文件看起来像这样:

<div ng-show="CurrentServices">
  <h3>{{CurrentServices.name}}</h3>

  <h4>Destinations</h4>

  <ul>
    <li ng-repeat="destination in CurrentServices.destinations">
      <a ng-href="#/airports/{{destination}}">{{destination}}</a>
    </li>
  </ul>
</div>

在公共文件夹的根目录下编辑index.html文件后,视图如下所示:

<html ng-app="ServiceCtrl">
<head>
  <title>Demo</title>
  <script type="text/javascript" src="js/lib/angular.min.js"></script>
  <script type="text/javascript" src="js/controllers/app.js"></script>
  <script type="text/javascript" src="js/controllers/destinations.js"></script>
  <script type="text/javascript" src="js/controllers/services.js"></script>
  <script type="text/javascript" src="js/controllers/reservations.js"></script>
  <script type="text/javascript" src="js/controllers/station.js"></script>
  <script type="text/javascript" src="js/app.js"></script>
  <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
  <link rel="stylesheet" type="text/css" href="css/bootstrap-responsive.min.css">
</head>
<body>
  <div class="container" ng-controller="AppCtrl">
    <h1>AngulAir</h1>

    <ul class="nav nav-pills">
      <li ng-class="destinationsActive">
        <a href="#">Destinations</a>
      </li>
      <li ng-class="servicesActive">
        <a href="#/services">services</a>
      </li>
      <li ng-class="reservationsActive">
        <a href="#/reservations">Reservations</a>
      </li>
    </ul>

    <div ng-view></div>
  </div>
</body>
</html>

在 Angular.js 中实现承诺

Promise 是关于如何将异步行为应用于应用的某个部分或整体。 还有许多其他的 JavaScript 库,其中承诺的概念是存在的,但在 Angular.js 中,它以比任何其他客户端应用更有效的方式出现。

在 Angular.js 中承诺有两种类型,一种是$q,另一种是 q。它们之间有什么区别? 我们将在下面的小节中详细探讨它。 现在,我们将看看 promise 对 Angular.js 意味着什么。

在 Angular.js 中有很多实现承诺的方法。 最常见的方法是使用$q参数,这是受到 Chris Kowal 的 Q 库的启发。 Angular.js 主要使用它来提供异步方法的实现。

在 Angular.js 中,服务的顺序是从上到下的,从$q开始,它被认为是顶级类; 在它内部,嵌入了许多其他子类,例如$q.reject()$q.resolve()。 在 Angular.js 中,所有与承诺相关的内容都必须遵循$q参数。

$q.when()方法开始,它似乎立即创建了一个方法,而不是只对可能创建或可能不创建 promise 对象的值进行规范化。 $q.when()的用法是基于提供给它的值。 如果提供的值是一个承诺,$q.when()将完成它的工作,如果不是,$q.when()将创建它。

在 Angular.js 中使用承诺的原理图

由于 Chris Kowal 的 Q 库是 promise 回调返回的全局提供者和灵感来源,Angular.js 也使用它来实现 promise。 很多 Angular.js 服务默认都是面向 promise 类型的。 这包括$interval$http$timeout。 然而,在 Angular.js 中有一个使用承诺的合适机制。 看看下面的代码,看看 promise 是如何在 Angular.js 中映射自身的:

var promise = AngularjsBackground();
promise.then(
  function(response) {
    // promise process 
  },
  function(error) {
    // error reporting 
  },
  function(progress) {
    // send progress

});

所有在 Angular.js 中提到的服务都返回一个 promise 对象。 它们可能在接受参数时有所不同,但作为回报,它们都在一个带有多个键的承诺对象中做出响应。 例如,当您提供四个名为datastatusheaderconfig的参数时,$http.get返回单个对象。

$http.get('/api/tv/serials/sherlockHolmes ')
  .success(function(data, status, headers, config) {
    $scope.movieContent = data;
});

如果我们在这里使用承诺的概念,同样的代码将被重写为:

var promise = $http.get('/api/tv/serials/sherlockHolmes ')
promise.then(
  function(payload) {
    $scope.serialContent = payload.data;
});

前面的代码比之前的代码更简洁,更容易维护,这使得 Angular.js 的使用更适合使用它的工程师。

Promise 作为 callback 的句柄

在 Angular.js 中,promise 的实现将 promise 定义为回调句柄。 这些实现不仅定义了如何在 Angular.js 中使用 promise,还定义了应该采取哪些步骤使服务成为“promise-return”。 这表示您异步执行某项任务,一旦您所述任务完成,您必须触发then()服务以结束您的任务或将其传递给另一个then()方法:/asynchronous _task.then().then().done()

在更简单的形式中,你可以这样做来实现 promise 作为回调句柄的概念:

angular.module('TVSerialApp', [])
  .controller('GetSerialsCtrl', 
    function($log, $scope, TeleService) {
      $scope.getserialListing = function(serial) {
        var promise = 
          TeleService.getserial('SherlockHolmes');
        promise.then(
          function(payload) { 
            $scope.listingData = payload.data;
          },
          function(errorPayload) {
            $log.error('failure loading serial', errorPayload);
        });
      };
  })
  .factory('TeleService', function($http) {
    return {

      getserial: function(id) {
        return $http.get(''/api/tv/serials/sherlockHolmes' + id);
      }
    }
  });

盲目传递参数和嵌套承诺

无论你使用什么承诺服务,你必须非常确定你传递的是什么,以及这个是如何影响承诺功能的整体工作的。 盲目地传递参数会导致控制器的混乱,因为它在处理其他请求时也必须处理自己的结果。 假设我们正在处理$http.get服务,而你盲目地将太多的负载传递给它。 因为它必须同时处理自己的结果,它可能会感到困惑,这可能会导致回调地狱。 但是,如果您想要对结果进行后处理,则必须处理一个名为$http.error的附加参数。 这样,控制器就不必处理它自己的结果,并且像 404 和重定向这样的调用将被保存。

你也可以通过构建你自己的承诺,并带回你选择的结果,你想要的有效载荷与以下代码:

factory('TVSerialApp', function($http, $log, $q) {
 return {
    getSerial: function(serial) {
      var deferred = $q.defer();
      $http.get('/api/tv/serials/sherlockHolmes' + serial)
        .success(function(data) { 
          deferred.resolve({
            title: data.title,
            cost: data.price});
        }).error(function(msg, code) {
            deferred.reject(msg);
            $log.error(msg, code);
        });
        return deferred.promise;
    }
  }
});

通过建立一个自定义的承诺,你有很多的发明。 您可以使用deferred.notify(mesg)方法控制输入和输出调用,记录错误消息,将输入转换为所需的输出,并共享状态。

延迟对象或组合承诺

由于 Angular.js 中的自定义承诺有时很难处理,在更糟糕的情况下可能会出现故障,所以 promise 提供了另一种实现自身的方式。 它要求您在then方法中转换您的响应,并以自主的方式将转换后的结果返回给调用方法。 考虑我们在前一节中使用的相同代码:

this.getSerial = function(serial) {
    return $http.get('/api/tv/serials/sherlockHolmes'+ serial)
        .then(
                function (response) {
                    return {
                        title: response.data.title,
                        cost:  response.data.price

                    });
                 });
};

我们从前面的方法产生的输出将是一个链接、承诺和转换。 您可以再次将输出重用为另一个输出,将其链接到另一个承诺,或者只是显示结果。

然后可以将控制器转换为以下代码行:

$scope.getSerial = function(serial) {
  service.getSerial(serial) 
  .then(function(serialData) {
    $scope.serialData = serialData;
  });
};

这大大减少了代码行数。 同时,这也有助于我们维护服务水平,因为then()中的自动安全机制将帮助它转换为失败的承诺,并将保持其余代码的完整性。

处理嵌套调用

当在success函数中使用内部返回值时,promise 代码可以感觉到你缺少一个最明显的东西:错误控制器。 丢失的错误可能会导致代码停滞不前或陷入无法恢复的灾难。 如果您想克服这个问题,只需抛出错误即可。 如何? 参见以下代码:

this.getserial = function(serial) {
    return $http.get('/api/tv/serials/sherlockHolmes' + serial)
        .then(
            function (response) {
                return {
                    title: response.data.title,
                    cost:  response.data.price
                });
            },
            function (httpError) {
                // translate the error
                throw httpError.status + " : " + 
                    httpError.data;
            });
};

现在,每当代码进入类似错误的情况,它将返回一个单一的字符串,而不是一串$http法规或配置细节。 这也可以节省您的整个代码进入停顿模式,并帮助您进行调试。 此外,如果您附加了日志服务,则可以查明导致错误的位置。

Angular.js 中的并发性

我们所有人都希望通过请求多个服务调用并从中获得结果,在单个时间段内实现最大输出。 Angular.js 通过它的$q.all服务提供了这个功能; 你可以一次调用多个服务,如果你想加入所有/任何服务,你只需要then()将它们按你想要的顺序组合在一起。

让我们先获取数组的有效载荷:

[ 
  { url: 'myUr1.html' },
  { url: 'myUr2.html' },
  { url: 'myUr3.html' }
]

下面的代码将使用这个数组:

service('asyncService', function($http, $q) {
     return {
       getDataFrmUrls: function(urls) {
         var deferred = $q.defer();
         var collectCalls = [];
         angular.forEach(urls, function(url) {
           collectCalls.push($http.get(url.url));
         });

         $q.all(collectCalls)
         .then(
           function(results) {
           deferred.resolve(
             JSON.stringify(results)) 
         },
         function(errors) {
           deferred.reject(errors);
         },
         function(updates) {
           deferred.update(updates);
         });
         return deferred.promise;
       }
     };
});

promise 是通过对每个 URL 执行$http.get创建的,并添加到数组中。 $q.all函数接受一个承诺数组的输入,然后将所有结果处理为一个包含每个答案的对象的单个承诺。 这将被转换成 JSON 并传递给调用者函数。

结果可能是这样的:

[
  promiseOneResultPayload,
  promiseTwoResultPayload,
  promiseThreeResultPayload
]

成功与失败的结合

$http返回一个承诺; 您可以根据这个承诺来定义它的成功或错误。 许多人认为这些功能是承诺的一个标准的部分,但实际上,它们并不是他们看起来的那样。

使用 promise 意味着你正在调用then()。 它接受两个参数—一个用于成功的回调函数和一个用于失败的回调函数。

想象一下这段代码:

$http.get("/api/tv/serials/sherlockHolmes")
.success(function(name) {
    console.log("The tele serial name is : " + name);
})
.error(function(response, status) {
    console.log("Request failed " + response + " status code: " + status);
};

这可以重写为:

$http.get("/api/tv/serials/sherlockHolmes")
.success(function(name) {
    console.log("The tele serial name is : " + name);
})
.error(function(response, status) {
    console.log("Request failed " + response + " status code: " + status);
};

$http.get("/api/tv/serials/sherlockHolmes")
.then(function(response) {
    console.log("The tele serial name is :" + response.data);
}, function(result) {
    console.log("Request failed : " + result);
};

一个可以使用successerror功能,这取决于的情况选择,但使用$http有一个好处,它是方便的。 其中error功能提供响应和状态,success功能提供响应数据。

这并不是承诺的标准部分。 任何人都可以将自己版本的这些函数添加到 promise 中,如下代码所示:

//my own created promise of success function

promise.success = function(fn) { 
    promise.then(function(res) {
        fn(res.data, res.status, res.headers, config);
    });
    return promise;
};

//my own created promise of error function

promise.error = function(fn) {  
    promise.then(null, function(res) {
        fn(res.data, res.status, res.headers, config);
    });
    return promise;
};

安全方法

因此,真正需要讨论的问题是如何使用$http? 成功或错误呢? 请记住,写承诺没有标准的方式; 我们必须考虑很多可能性。

如果你改变你的代码,使你的承诺不返回从$http,当我们加载数据从缓存,你的代码将崩溃,如果你预期成功或错误在那里。

所以,最好的方法是尽可能使用then。 这不仅概括了编写承诺的总体方法,而且还减少了代码中的预测元素。

兑现你的承诺

Angular.js 有最好的特性来传递你的承诺。 当您同时处理多个承诺时,此功能很有帮助。 下面是如何通过以下代码实现路由:

$routeProvider
  .when('/api/', {
      templateUrl: 'index.php',
      controller: 'IndexController'
  })
  .when('/video/', {
      templateUrl: 'movies.php',
      controller: 'moviesController'
  })

如你所见,我们有两条路线:api路线带我们到索引页,有IndexController,以及视频路线带我们到电影页面。

app.controller('moviesController', function($scope, MovieService) {  
    $scope.name = null;

    MovieService.getName().then(function(name) {
        $scope.name = name;
    });
});

有一个问题,在MovieService类从后端获取名称之前,名称是null。 这意味着如果我们的视图绑定到名称,首先它是空的,然后它被设置。

这就是路由的用武之地。 路由解决了名称设置为null的问题。 我们可以这样做:

var getName = function(MovieService) {  
       return MovieService.getName();
   };

$routeProvider
  .when('/api/', {
      templateUrl: 'index.php',
      controller: 'IndexController'
  })
  .when('/video/', {
      templateUrl: 'movies.php',
      controller: 'moviesController'
  })

添加解析后,我们可以重新编写控制器代码:

app.controller('MovieController', function($scope, getName) {

    $scope.name = name;

});

你也可以为你承诺的路由定义多个解析,以获得最好的可能输出:

$routeProvider
  .when('/video', {
      templateUrl: '/MovieService.php',
      controller: 'MovieServiceController',
      // adding one resole here
      resolve: {
          name: getName,
          MovieService: getMovieService,
          anythingElse: getSomeThing
      }
      // adding another resole here
       resolve: {
          name: getName,
          MovieService: getMovieService,
          someThing: getMoreSomeThing
      }
  })

小结

在本章中,我们学习了承诺是如何在 Angular.js 中实现的,它是如何发展的,以及承诺如何帮助创建用于实时 web 应用的应用。 我们还看到了 Q 库的功能和 Angular.js 使用代码实现的承诺,并学习了如何在我们的下一个应用中使用它们。

Angular.js 中的 promise 规范非常接近 ECMAScript 6 提出的规范,但当 Angular.js 完全将 promise 作为自己的规范时,可能会有变化。 它将定义自己的一组使用承诺的规则,这些规则可能与规范本身不同。

在下一章中,我们将探讨如何在 jQuery 中实现承诺,它的机制是什么,以及它将带来什么好处。