`
youyu4
  • 浏览: 440545 次
社区版块
存档分类
最新评论

AngularJS中的服务 -- $q

 
阅读更多

描述

译者注: 看到了一篇非常好的文章,如果你有兴趣,可以查看: Promises与Javascript异步编程 , 里面对Promises规范和使用情景,好处讲的非常好透彻,个人觉得简单易懂。

既然是用来处理异步编程的,那么在浏览器端的JS里,主要是2种: setTimeout 和 Ajax 请求.  promise 的使用就很像Ajax请求的成功和失败回调。

 

此承诺/延迟(promise/deferred)实现的灵感来自于  Kris Kowal's Q CommonJS Promise建议文档 将承诺(promise) 作为和 异步执行操作(action)结果对象进行交互的接口,在指定的时间内可能完成也可能不能够完成(如超时,错误,拦截等等)。

从错误处理的角度看,延迟(deferred )和承诺(promise ) API 对于异步编程来说, 和同步编程的 try,catch, 以及throw作用差不多.

[javascript] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. // 为了演示的目的,此处我们假设 `$q`, `scope` 以及 `okToGreet` 引用 在当前执行环境中可用  
  2. // (比如他们已经被注入,或者被当做参数传进来了).  
  3.    
  4. function asyncGreet(name) {  
  5.   var deferred = $q.defer();  
  6.    
  7.   setTimeout(function() {  
  8.     // 因为此function 在未来的事件循环中异步执行,  
  9.     // 我们需要把代码包装到到一个 $apply 调用中,以便正确的观察到 model 的改变  
  10.     scope.$apply(function() {  
  11.       deferred.notify('即将问候 ' + name + '.');  
  12.    
  13.       if (okToGreet(name)) {  
  14.         deferred.resolve('你好, ' + name + '!');  
  15.       } else {  
  16.         deferred.reject('拒绝问候 ' + name + ' .');  
  17.       }  
  18.     });  
  19.   }, 1000);  
  20.    
  21.   return deferred.promise;  
  22. }  
  23.    
  24. var promise = asyncGreet('小漠漠');  
  25. promise.then(function(greeting) {  
  26.   alert('成功: ' + greeting);  
  27. }, function(reason) {  
  28.   alert('失败鸟: ' + reason);  
  29. }, function(update) {  
  30.   alert('收到通知: ' + update);  
  31. });  


引人这种额外的复杂性的效果 在起初可能不明显。 在 promise 和 deferred APIs 进行承诺时好处就看出来了,请参考:  https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md
另外 promise api允许那些在传统的回调( CPS )方法中很难的实现的组合。 更多信息请查阅 Q文档 ,特别是 串行与并行的合并一节。

延迟接口 | Deferred API

通过调用  $q.defer() 可以构建一个新的 deffered 实例。
deffered 对象用来将 Promise 实例与 标记任务状态(执行成功还是不成功)的 API 相关联。

deffered 对象的方法

  • resolve(value) ——传入 value 解决派生的 promise。 如果 value 是一个通过 $q.reject 构造的拒绝对象(rejection) , 该promise 将被拒绝。
  • reject(reason) ——拒绝派生的promise,并提供原因 。 这相当于通过 $q.reject构造的拒绝对象(rejection)作为参数传递给 resolve。
  • notify(value)  ——在 promise 执行的过程中提供状态更新。 这在 promise 被解决或拒绝之前可能会被多次调用。

deffered 对象的属性

promise – {Promise} —— 与延迟(deferred)相关联的 promise 对象。

承诺 接口 | Promise API

当创建 deferred 实例时会创建一个新的 promise 对象,并可以通过  deferred.promise 得到该引用。
promise 对象的目的是在 deferred 任务完成时,允许感兴趣的部分取得其执行结果。

promise 对象的方法

  • then(successCallback, errorCallback, notifyCallback) ——不管 promise 是被处理还是被拒绝, 一旦结果可用,then 就会尽快地异步调用 成功/错误 回调函数 只要结果是可用的。 调用回调函数时传递单个参数: 结果 或拒绝的理由。 此外,notify 回调可能被调用 0到多次,以提供 提供一个进度指示,之前承诺解决或拒绝。

           这个方法 返回一个新的promise 对象, 根据 successCallback , errorCallback的返回值进行解决或拒绝 。 它还通过 notifyCallback 方法的返回值进行通知。 promise 不能从notifyCallback方法得到解决或拒绝 。

  • catch(errorCallback) —— promise.then(null, errorCallback) 的快捷方式
  • finally(callback) ——让你可以观察到一个 promise 是被执行还是被拒绝, 但这样做不用修改最后的 value值。 这可以用来做一些释放资源或者清理无用对象的工作,不管promise 被拒绝还是解决。 更多的信息请参阅完整文档规范.

            因为在 ES3版本的JavaScript中 finally 是一个保留字关键字,不能作为属性名,为了适配 IE8,您需要使用  promise['finally'](callback) 这种形式来调用该方法。

promise 链 | Chaining promises

因为调用一个 promise 的 then 方法返回一个新的派生 promise实例,所以构建promises链也是很容易的:

[javascript] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. promiseB = promiseA.then(function(result) {  
  2.   return result + 1;  
  3. });  
  4.    
  5. // promiseB 将会在处理完 promiseA 之后立刻被处理,  
  6. // 并且其  value值是promiseA的结果增加1  

我们可以创建任意长度的promise链;因为一个promise可以被另一个promises处理(进一步推迟解决完成时间),所以在promise链上的任意一点进行 暂停/推迟解决 都是可行的。 这使得实现功能强大的APIs 成为现实,例如  $http 的响应拦截器。

Kris Kowal's Q 与 $q 之间的区别

主要区别有两点:

  • Angular中的$q 集成了 ng.$rootScope.Scope  Scope模型观察机制,这意味着对models 的解决或拒绝速度将会更快,避免不必要的浏览器重绘(会导致UI闪烁)。
  • Q 比 $q拥有更多的功能特性,但带来的是代码字节数的增加。 $q 很轻量级,但包含了一般异步任务所需的所有重要功能。

     测试

[javascript] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. it('should simulate promise', inject(function($q, $rootScope) {  
  2.   var deferred = $q.defer();  
  3.   var promise = deferred.promise;  
  4.   var resolvedValue;  
  5.    
  6.   promise.then(function(value) { resolvedValue = value; });  
  7.   expect(resolvedValue).toBeUndefined();  
  8.    
  9.   // 模拟 promise 的 resolving  
  10.   deferred.resolve(123);  
  11.   // 注意 'then' function 不是同步调用的.  
  12.   // 因为我们想要  promise API 一直是异步的(async),  
  13.   // 不管是在同步调用还是异步调用中都是如此.  
  14.   expect(resolvedValue).toBeUndefined();  
  15.    
  16.   // 使用 $apply()将 promise resolution 传递到 'then' functions .  
  17.   $rootScope.$apply();  
  18.   expect(resolvedValue).toEqual(123);  
  19. }));  

依赖关系 | Dependencies

$rootScope 

方法 | Methods

all(promises)

结合多个promises为单个promise,在所有输入的promise都处理之后,组合之后的promise才会处理完成。

  • 参数: promises
  • 类型: Array.<Promise>/Object.<Promise>
  • 描述: promises的数组或者引用
  • 返回: Promise 返回单个的 promise,将与一个数组解决/散列值, 每个值对应于在相同的索引/关键的承诺 承诺 /散列数组。 如果任何承诺解决排斥,这产生的承诺将被拒绝 拒绝相同的值。

defer()

创建一个 递延 对象代表一个将来完成任务。

  • 返回  Deferred 返回一个新实例的Deferred。

reject(reason)

创建一个指定拒绝原因的promise. 此api应该用于在一个promises链中进行拒绝。 如果你正在处理promise 链中的最后一个promise,你不需要担心。

把  deferreds/promises 与我们熟悉的的 try/catch/throw行为进行对比,可以认为 reject 相当于 JavaScript 中的throw 关键字。 这也意味着如果你通过一个 promise 的 error回调,  “catch”了一个错误 ,你想要指明当前的承诺已经执行出错了,就必须重新抛出一个“附带了错误信息,拒绝通过的reject” 。

[javascript] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. promiseB = promiseA.then(function(result) {  
  2.   // success: 此处可以执行某些操作,然后直接使用原有的result,  
  3.   // 或者对result进行操作,来处理接下来的promiseB  
  4.   return result;  
  5. }, function(reason) {  
  6.   // error: handle the error if possible and  
  7.   //        resolve promiseB with newPromiseOrValue,  
  8.   //        否则转向拒绝 promiseB 的分支  
  9.   if (canHandle(reason)) {  
  10.    // 处理错误和恢复  
  11.    return newPromiseOrValue;  
  12.   }  
  13.   return $q.reject(reason);  
  14. });  
  • 参数: reason
  • 类型: *
  • 描述: Constant, message, exception 或代表拒绝原因的 object。
  • 返回: Promise    返回一个promise ,已经因为 reason 而被拒绝了 。

when(value)

将一个对象(可能是value 或  [第三方]then-able promise) 包装为一个 $q promise。 这在你不确定所处理的对象是否是一个promise 时是很有用的,有可能该对象来自于一个不被信任的源头。

  • 参数: value
  • 类型: *
  • 描述: promise 的值
  • 返回 Promise    根据传入的值/或promise 返回一个包装后的 promise
分享到:
评论

相关推荐

    AngularJS 中的Promise --- $q服务详解

    在AngularJS中,Promise的实现是通过`$q`服务来完成的。 首先,Promise有三个核心状态:pending(等待中),fulfilled(已成功)和rejected(已失败)。一旦Promise的状态从pending变为fulfilled或rejected,这个...

    angularjs-routing-源码.rar

    2. **`$q`服务**:`resolve`中的函数通常返回一个`Promise`,利用`$q`服务来处理异步操作。 六、总结 理解AngularJS的路由机制,不仅有助于我们编写高效、灵活的应用,还能在遇到问题时迅速定位原因。通过对`$...

    用AngularJS开发下一代Web应用(AngularJS 2013)-中英双版本

    AngularJS中的服务可以通过依赖注入的方式被其他组件使用,无需关心它们如何被创建或管理。这种设计模式使得代码的可测试性和可维护性大大增强,同时也降低了组件之间的耦合度。 模块化是AngularJS组织应用的基石。...

    AngularJs 1.5.8

    7. **服务**:AngularJS 1.5.8提供了多种内置服务,如$http用于处理HTTP请求,$q用于异步编程,$rootScope是所有控制器共享的根作用域等。这些服务极大地丰富了框架的功能。 8. **过滤器**:过滤器用于格式化和转换...

    angularjs-FlightDashboard, 带有 AngularJS $q 演示,源代码,&教程的Promise链.zip

    angularjs-FlightDashboard, 带有 AngularJS $q 演示,源代码,&教程的Promise链 简介承诺是解决异步请求和响应复杂性的一个很好的解决方案。 AngularJS使用 $q 和 $http 等服务提供承诺;其他服务也使用承诺,但我...

    AngularJS-Weather-App:在 David Souther 的帮助下开发的 AngularJS 天气 APP

    - **$q** 服务:处理异步操作,支持 Promise API。 4. **API 调用** - **天气 API**:该应用可能使用了 OpenWeatherMap 或其他天气 API 来获取实时天气信息。 - **JSON 格式**:API 返回的数据通常为 JSON 格式...

    angularjs-chapter6-示例.rar

    本资源“angularjs-chapter6-示例.rar”专注于讲解AngularJS的第六章,这一章通常涉及数据绑定、指令、服务、过滤器等核心概念的深入实践。通过解压文件,我们可以看到一个名为“chapter8”的子目录,这可能是因为...

    解决Angularjs异步操作后台请求用$q.all排列先后顺序问题

    $q是AngularJS中用于处理promise对象的模块,而promise是一种用于处理异步编程的方式。在AngularJS中,开发者经常需要处理与服务器端的异步通信,比如HTTP请求。这些请求往往需要按特定顺序执行,以确保数据的正确性...

    angularjs-tdd-open-assignment-solution

    6. **服务**:用于封装应用的业务逻辑和数据,如$http服务用于HTTP请求,$q服务用于异步操作的承诺(Promise)。 7. **测试**:使用Karma设置测试环境,编写Jasmine测试用例,涵盖控制器、服务、指令等组件的测试。...

    angularjs-springboot-CreditScoreApp

    3. **服务**:提供依赖注入,如$http服务用于向后端发送HTTP请求,$q服务用于处理异步操作。 4. **模块化**:通过模块管理应用的各个部分,便于代码组织和复用。 5. **表单验证**:AngularJS内置的表单验证机制,...

    angularjs文件及参考文档ui-router

    - **AngularJS基础**:了解数据绑定、指令、服务、过滤器和控制器的概念,以及它们在实际应用中的作用。 - **模块化**:掌握如何创建和组织AngularJS模块,以及模块间的服务共享。 - **依赖注入**:理解AngularJS的...

    SoftUni---SPA-with-AngularJS---HomeworksSolutions:在 SoftUni 上使用 AngularJS 课程为 SPA 提供家庭作业解决方案

    6. **服务**:AngularJS中的服务是可重用的组件,它们可以跨控制器共享数据和行为,如$http服务用于与服务器进行HTTP通信,$q服务用于处理异步操作。 7. **表达式**:AngularJS的模板语言允许在HTML中直接插入...

    用AngularJS开发下一代web应用源码

    - **服务**:AngularJS中的服务(如$http、$resource、$q等)提供了对常见任务的抽象,如HTTP请求、数据缓存和异步操作。 2. **使用Sublime编辑器**: - **Ctrl+Shift+F全局搜索**:在Sublime中,这个快捷键可以...

    详解AngularJS如何实现跨域请求

    本文将详细讲解AngularJS中的$http服务如何实现跨域请求。 首先,我们来看AngularJS中的核心服务$http。它是一个基于XMLHttpRequest对象(XHR)的HTTP服务,用于与服务器进行异步数据交互。例如,我们可以使用$...

    angularjs-up

    在AngularJS中,应用始于模块,模块是组织代码的基本单位,可以包含控制器、服务、指令、过滤器等。 3. **控制器(Controller)** 控制器是业务逻辑的主要载体,与$scope对象交互,负责处理用户交互和数据模型。 ...

    AngularJS中update两次出现$promise属性无法识别的解决方法

    这通常是因为你的Java实体类没有定义这个字段,而AngularJS中的服务在处理响应时添加了这个字段。 **二、问题产生的原因** 1. **两次更新**:当使用AngularJS的`$http`或`$resource`服务进行更新操作时,如果连续...

    详解Javacript和AngularJS中的Promises

    AngularJS中使用$q服务的一个典型例子是: ```javascript var deferred = $q.defer(); someAsyncFunction(function(result) { deferred.resolve(result); // 异步操作成功 }, function(err) { deferred.reject...

    angularjs-requirejs-seed:angularjs 和 requirejs 的种子应用程序

    4. **服务**:AngularJS的服务提供了一种抽象,可以用来封装复杂的功能,如$http服务用于发送HTTP请求,$q服务用于处理异步操作。 **RequireJS关键功能** 1. **模块化**:RequireJS通过AMD规范实现了JavaScript的...

    AngularJS 中文手册.zip

    AngularJS的服务是可注入的单例对象,它们提供了通用功能,如$http服务用于异步数据请求,$timeout和$interval用于定时任务,$q服务处理Promise对象等。 5. **表达式** AngularJS的模板中使用双大括号`{{ }}`来...

    angularJS中文API帮助文档

    AngularJS内建了一些服务,如$http、$q(Promise服务)和$resource(用于与RESTful API交互)。 6. **过滤器**:过滤器用于转换数据,如`currency`用于格式化货币,`date`用于格式化日期,`limitTo`用于截取字符串...

Global site tag (gtag.js) - Google Analytics