angularjs系列之轻松使用$q进行异步编程

2023-11-06

angularjs系列之轻松使用$q进行异步编程

来源:网络    编辑:admin

 第一部分关于js中的异步编程


  异步编程简单的说就是你写了一段代码,但他不会按照你书写代码的顺序立即执行,而是等到程序中发生了某个事件(如用户点击了某个按钮,某个ajax请求得到了响应)才去执行这段代码,而且这段代码可能执行一次(如一个ajax请求得到了响应)、也可能执行很多次或者不执行(一个按钮被点击了许多次或者0次)这就是所谓的异步编程。


  有两种异步程序模式单次执行模式监听执行模式。像ajax请求这样的就是属于单次执行模式,请求、回调只会进行一次。像事件绑定就属于监听执行模式,只要事件发生回调就可以不断的执行。但是不管是单次执行模式还是监听执行模式在js程序中的共同点都是保存着一个函数引用(这个引用的表现形式就回调函数),在某个事件发生后开始执行这个函数引用中的代码。


  下面给出这两种模式的整体模型图:



  异步执行体:包含异步执行代码(或者异步动作)和状态,状态不可逆。


  回调执行体:包含回调执行代码和状态,状态不可逆。


  两种执行体是依靠异步执行体发送信号通信。


  监听执行模式和单次执行模式的区别:监听模式中会有多个异步执行体和回调执行体副本,且每个异步执行体副本关联一个回调执行体副本。多个副本的这两种执行体的执行代码是一样的,唯一区别的就是每个副本的状态不同。


  代码举例:



//单次执行模式:
funtion a(b) {
       console.log(“a process”);
       b();
};
function b() {
       console.log(“b process”);
};
a(b); //发送信号
//监听执行模式(这里直接使用jquery):
$(“#button”).bind(“click”, function() {
       console.log(“click callback”);
});
$(“#button”).trigger(“click”); //发送信号



第二部分关于promise模式的异步编程


  上面就是异步编程的两种形式,由于我们的$q是解决第一种模式中存在的问题的,所以这里就讨论讨论单次执行模式中存在的问题。你可以设想这么一种场景,当你要在很多个ajax请求响应完成后做一件事情,你用现有的js的回调方式,会不会发现回调的层次很深、代码十分混乱。而然我们promise模式的异步编程方式就能很好的管理这些单次执行模式下的代码,使你的代码书写起来更加优雅,说白了promise不产生新的东西只是一个语法糖使你编写出更加优雅的异步程序代码。


  那promise模式到底是什么样的呢,说白了就是把把我上面的单次执行模式图抽象化了,用一个defer对象(延期对象)代表异步执行体,用一个promise对象(承诺对象)代表回调执行体,这个defer对象可以发送消息,promise接受消息,然后执行相应的回调函数。Promise就是异步执行体和回调执行体之间的桥梁,这样的好处是异步执行体和回调执行体这种模型很好的对异步动作和回调动作进行了解耦。你可以在promise上面好好的操纵你的回调执行体,而只是接受一个来自defer发送的参数。


  这里还不能很好的体现出promise模式的优势,而她真正的优势是在这种模型下扩充的api使其发挥了真正的强大作用。比如说promise对象的then方法,这个方法就是支持异步链式编程最重要的方法,他也是使代码更加优雅最重要的方法。还有比如说all接收一个promise数组返回一个新的promise,当前面的所有promise状态都完成之后这个新的promise才能完成,这个很适合多个ajax后处理某些事情。不过可能你还不能明白,下面在介绍$qAPI的时候有详细的介绍。


第三部分 $q服务的API详解


  下面我们通过讲解$q的API让你更多的了解promise异步编程模式。$q是做为angularjs的一个服务而存在的,只是对promise异步编程模式的一个简化实现版,源码中剔除注释实现代码也就二百多行,下面开始介绍$q的API。


     defer对象(延迟对象)可以通$q.defer()获取,下面是defer对象的api:


     方法:


     resolve(value):向promise对象异步执行体发送消息告诉他我已经成功完成任务,value即为发送的消息。


     reject(value): 向promise对象异步执行体发送消息告诉他我已经不可能完成这个任务了,value即为发送的消息。


     notify(value): 向promise对象异步执行体发送消息告诉他我现在任务完成的情况,value即为发送的消息。


  这些消息发送完promise会调用现有的回调函数。


     属性:


     promise即与这个defer对象的承诺对象。


  从上可以看出defer主要是用来发送消息的。


  promise对象可以通过defer.promise获取,下面是promise对象的api:


  方法:


  then(successCallback,errorCallback,notifyCallback):参数为不同消息下的不同回调函数,defer发送不同的消息执行不同的回调函数,消息作为这些回调函数的参数传递。返回值为回一个promise对象为支持链式调用而存在。当第一个defer对象发送消息后,后面的promise对应的defer对象也会发送消息,但是发送的消息不一样,不管第一个defer对象发送的是reject还是resolve,第二个及其以后的都是发送的resolve,消息是可传递的。


  catch(errorCallback):then(null,errorCallback)的缩写。


  finally(callback):相当于then(callback,callback)的缩写,这个finally中的方法不接受参数,却可以将defer发送的消息和消息类型成功传递到下一个then中。


  代码举例:




function f1(num) {
       document.write("success:" + (num++) + "<br/>");
       return num;
}
function f2(num) {
       document.write("errror:" + (num++) + "<br/>");
       return num;
}
var defer = $q.defer();
var promise = defer.promise;
//方式1
// promise.then(f1,f2).then(f1,f2);
// 方式2
// promise.then(f1,f2);
// promise.then(f1,f2);
// 方式3
// promise.then(f1,f2).then(f1,f2);
// promise.catch(f2);
// promise.finally(f2);
//方式4
// promise.finally(f2).then(f1,f2);
defer.reject(1);
方式1的结果:
errror: 1
success: 2
方式2的结果:
errror: 1
errror: 1
方式3的结果:
errror: 1
errror: 1
error: NaN
success: 2
方式4的结果:
Error: NaN
Error: 1  




  现在继续$q的api:


  方法:


  defer():用来生成一个延迟对象 var defer =$q.defer();


  reject():参数接收错误消息,相当于在回调函数中抛出一个异常,然后在下一个then中调用错误的回调函数。


  代码举例:




var defer = $q.defer();
var promise = defer.promise;
promise.then(function() {
       return $q.reject("success error");
}, function() {
       return $q.reject("error error");
}).then(function(info) {
       document.write("s:" + info + "<br/>");
}, function(info) {
       document.write("e:" + info + "<br/>");
});
//方式1
// defer.reject(1);
//方式2
// defer.resolve(1);
方式1运行结果
e: error error
方式2运行结果
e: success error



  



  all()参数接收为一个promise数组,返回一个新的单一promise对象,当这些promise对象对应defer对象全部解决这个单一promise对象才会解决,当这些promise对象中有一个被reject了,这个单一promise同样的被reject了。


  代码举例:




var defer1 = $q.defer();
var promise1 = defer1.promise;
promise1.then(function(num) {
              console.log("success" + num);
       },
       function(num) {
              console.log("error" + num);
       });
var defer2 = $q.defer();
var promise2 = defer2.promise;
promise1.then(function(num) {
              console.log("success" + num);
       },
       function(num) {
              console.log("error" + num);
       });
var promise3 = $q.all([promise1, promise1]);
promise3.then(function(num) {
       console.log("s:" + num);
}, function(num) {
       console.log("e:" + num);
});
//方式1
// defer1.resolve(1);
// defer2.resolve(1);
//方式2 
//defer1.reject(1);
方式1的结果:
success1
success2: 1
s: 1,
1
方式2的结果:
error1
e: 1



  



  when():接收第一个参数为一个任意值或者是一个promise对象,其他3个同promise的then方法,返回值为一个promise对象。第一个参数若不是promise对象则直接运行success回调且消息为这个对象,若为promise那么返回的promise其实就是对这个promise类型的参数的一个包装而已,被传入的这个promise对应的defer发送的消息,会被我们when函数返回的promise对象所接收到。


  代码举例:




var promise = $q.when(1, function(num) {
       console.log("s" + num);
}, function() {
       console.log("e");
});
var defer1 = $q.defer();
var promise1 = defer1.promise;
var promise2 = $q.when(promise1, function(num) {
       console.log("s" + num);
}, function() {
       console.log("e");
});
defer1.reject(1);
运行结果:
s1
e




  对上面还有一个注意事项就是defer对象发送消息不会立即执行的,而是把要执行的代码放到了rootScope的evalAsync队列当中,当时scope.$apply的时候才会被promise接收到这个消息。


  到这里$q服务全部介绍完了,对于angular中的then的链式调用中如果defer发送的reject的那么只有第一个promise是reject的回调,其他的都是resolve的回调这里多少觉得是不合适的,不知道是个bug还是就是这样设计?$q只适合单次执行模式,不知道是否适合扩展成监听执行模式?这都是大家值得思考的问题。


转载于:https://my.oschina.net/felumanman/blog/336518

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

angularjs系列之轻松使用$q进行异步编程 的相关文章

  • 在 Three.js 中绕点旋转对象的正确方法是什么?

    关于 Three js 的大多数教程 问题都建议使用 Three js 绕点旋转对象的方法是在要旋转的位置创建父对象 附加对象 然后移动子对象 然后 当父级旋转时 子级围绕该点旋转 例如 Make a pivot var pivot new
  • 将 Javascript 对象的属性从 string 更改为 int

    我有一个对象数组 每个对象具有三个属性 年份 总计 人均 例子 0 Object per capita 125 8 total 1007 2 year 2009 这些属性是字符串 我想创建一个循环来遍历数组并将它们转换为 int 我尝试了以
  • JavaScript 添加布尔值

    console log true true 2 console log typeof true true number console log isNaN true true false 为什么两个布尔类型相加会产生一个数字 我有点理解 如
  • 使用 Angular 指令禁用文本选择

    我正在学习 JavaScript 和 AngularJS 我想使用 Angular Directive 禁用文本选择 我有该函数的 JavaScript 代码 function clearSelection if document sele
  • 在版本 4.4.6 中禁用 ckeditor 上下文菜单

    我在 Rails4 项目中使用 ckeditor 我尝试了 ckeditor gem 和 ckeditor rails gem 来提供 ckeditor 库 这里有多个帖子 人们希望删除 ckeditor 上下文菜单 以便可以显示本机浏览器
  • 本地推送通知到在应用程序内运行 JS 代码的 Win8 Live Tile

    我正在尝试将更新发送到我的应用程序的磁贴 当应用程序运行时 这可以正常工作 例如 当用户单击按钮时 我可以轻松地将磁贴更新通知发送到磁贴 我无法解决的是当应用程序无法运行时如何更新磁贴 我找到的唯一选择是使用以下命令从远程 Web 服务器拉
  • JavaScript 验证和 PHP 验证?

    我正在使用 jquery 验证插件来验证空表单 我还应该在 PHP 中检查一下以确保 100 正确吗 或者用 javascript 验证就可以了 谢谢 您应该始终在服务器上进行验证 如果用户以某种方式不使用 Javascript 提交表单
  • javascript 选择自定义光标 (svg)

    我正在动态地将光标更改为悬停时的本地 svg element on mouseover function this css cursor url svgs pointer svg 9 30 auto 工作正常 但我想选择该 svg 来操纵其
  • React Router v4 不渲染组件

    React Router v4 渲染组件存在问题 在应用程序初始加载时 它将呈现与 URL 相对应的正确组件 但是 任何后续的组件Link单击不会呈现所需的组件 图书馆 反应路由器 4 2 2 https reacttraining com
  • JavaScript推送函数中的动态变量

    我在 JavaScript 中使用推送功能 var chartData for var i 0 i lt 3 i chartData push date new Date year s mon s date s hr s min s sec
  • mongodb 聚合 - 累积字段的不同组值

    如果我有Player表格文件 name String score Int 我有Group文档 其中组代表玩家列表 groupName String players ObjectID 玩家可以属于多个组 我想做一个聚合Player文档 按以下
  • 如何始终将焦点保持在文本框中

    我创建了一个包含两个 div 的 HTML 页面 左侧的 div 页面的 90 是 ajax 结果的目标 右侧的 div 页面的 10 包含一个文本框 该页面的想法是在文本框中输入零件编号 通过条形码扫描仪 并显示与该零件编号匹配的绘图 显
  • 如何正确取消引用然后删除 JavaScript 对象?

    我想知道从内存中完全取消引用 JavaScript 对象的正确方法 确保删除时不会在内存中悬空 并且垃圾收集器会删除该对象 当我看这个问题时在 JavaScript 中删除对象 https stackoverflow com questio
  • 如何计算特定字符在字符串中出现的次数

    我正在尝试创建一个函数来查看数组中的任何字符是否在字符串中 如果是 有多少个 我尝试计算每一种模式 但是太多了 我尝试使用 Python 中的 in 运算符的替代方案 但效果不佳 function calc fit element var
  • 使用 Google 日历源时如何禁用 FullCalendar 中的活动链接?

    我正在使用 FullCalendar 库从 Google 日历加载日历中的事件 不幸的是 事件添加到日历后 它们是可点击的 当您点击该活动时 您会自动重定向到 Google 日历页面以查看该特定活动 或者如果您有足够的访问权限 则可以直接对
  • 用于选择特定 div 中具有特定类的锚元素的 jQuery 选择器是什么

    我有一些这样的代码 我想选择每个 a 带有类的标签status在 div 中foo div a class status a div 你可以这样做 foo find status a
  • 有没有办法使用 ko.observableArray 作为地图?

    有没有办法使用ko observableArray http knockoutjs com documentation observableArrays html像地图 字典一样 例如 var arr ko observableArray
  • 什么是 WKWebView 中的 WKErrorDomain 错误 4

    fatal error LPWebView encounters an error Error Domain WKErrorDomain Code 4 A JavaScript exception occurred UserInfo 0x7
  • 如何从 json 文件创建模型? (ExtJS)

    这是我想使用 json 文件创建的模型 Ext define Users extend Ext data Model fields name user id type int name user name type string 为了根据服
  • 没有输入的 jQuery 日期选择器

    我有一个相当复杂的网络应用程序 我想向其中添加一些日期选择 UI 我遇到的问题是我无法从文档中弄清楚如何真正控制日期选择器的出现方式和时间 不涉及任何表单元素 不 我不会添加秘密表单字段 因此简单的开箱即用方法根本行不通 我希望有人可以提供

随机推荐

  • 谷歌取消了2000多人的offer,特殊时期如何应对裁员?

    就在刚刚 CNBC报道 科技大厂谷歌有上千人饭碗保不住了 图片来自NBC 版权属于原作者 谷歌缩减招聘 据悉这部分人主要是谷歌的合同工和临时工 纽约时报 报道 谷歌取消了2000多人的工作录取 上个月 谷歌首席执行官劈柴君向员工承认 由于新
  • 字符串 字符串中的第一个唯一字符

    LC 字符串中的第一个唯一字符 给定一个字符串 s 找到 它的第一个不重复的字符 并返回它的索引 如果不存在 则返回 1 Swift 实现 func firstUniqChar s String gt Int 创建字符数组 var arra
  • [HTTP] 01一张思维导图带你领略HTTP发展史

    HTTP是什么 HTTP作为一个较常见的应用协议 在面试过程中经常会对其相关内容进行考察 其发展史亦是重点 HTTP是什么 HTTP为Hyper Text Transfer Protocol的简写 中译超文本传输协议 是在计算机网络里面点对
  • 网络原理:ISO/OSI参考模型

    1 ISO OSI参考模型 1 1 各层功能 1 物理层功能 物理层是OSI参考模型的最低层 它利用传输介质为数据链路层提供物理连接 保证二进制位流的透明传送 2 数据链路层 数据链路层是为网络层提供服务的 解决两个相邻结点之间的通信问题
  • C# 学习笔记--个人学习使用 <1>

    C 学习笔记 Chapter 1 C 比较软的基础部分 Section 1 类与命名空间 Part 1 命名空间 NameSpace Part 2 类 Class Section 2 基本元素 Section 3 数据类型 Part 1 什
  • 使用opencv rotate函数实现图片旋转

    使用rotate函数 旋转图片 rotate src dst ROTATE 90 CLOCKWISE 使用rotate 旋转图片 src是源图片的mat dts是目标图片的mat 第3个参数是旋转的角度 有以下4个选项 ROTATE 90
  • android app缓存机制会自动清除,深入理解Android缓存机制(一)缓存简介

    概述 说起缓存 大家可能很容易想到Http的缓存机制 LruCache 其实缓存最初是针对于网络而言的 也是狭义上的缓存 广义的缓存是指对数据的复用 我这里提到的也是广义的缓存 比较常见的是内存缓存以及磁盘缓存 不过要想进一步理解缓存体系
  • Python内置函数详解,进阶必备

    内置函数就是Python给你提供的 拿来直接用的函数 比如print input等 截止到python版本3 6 2 python一共提供了68个内置函数 具体如下 本文将这68个内置函数综合整理为12大类 正在学习Python基础的读者一
  • 关于SDC时钟约束的事

    1 quartus的SDC约束就跟xilinx的ucf约束文件一样 2 主要用途一般是 一从输入端口到寄存器 二寄存器到寄存器 通过设定时钟频率方式进行约束 三寄存器到输出 四创建时钟约束命令 五时钟延迟约束 六时钟抖动约束 七输入和输出延
  • Android实现简单的相册

    用手机浏览靓照也是件非常惬意的事了 然而如何实现这一功能呢 其实也并不难 下面是一个简单的例子 功能为 主屏幕上显示用户选择的靓照 屏幕下面滚动显示靓照集 点击即可浏览 如下图所示 实现代码为 这里图片没法提供了 可以设置自己喜欢的图片 R
  • MYSQL查询优化器

    MYSQL 逻辑结构 MySQL 使用典型的客户端 服务器 Client Server 结构 体系结构大体可以分为三层 客户端 服务器层以及存储引擎层 其中 服务器层又包括了连接管理 查询缓存 SQL 接口 解析器 优化器 缓冲与缓存以及各
  • Navicat连接Mysql遇到的错误

    在navicat链接mysql以后的版本时 会出现2059的错误 这个错误出现的原因是在mysql8之前的版本中加密规则为mysql native password 而在mysql8以后的加密规则为caching sha2 password
  • mysql内测试连通性命令_怎么使用ping命令进行连通性测试

    关于ping命令的作用 ping 命令有助于验证网络层的连通性 一般进行网络故障排除时 可以使用ping 命令向目标计算机或IP地址发送ICMP回显请求 目标计算机会返回回显应答 如果目标计算机不能返回回显应答 说明在源计算机和目标计算机之
  • python提取txt文件中的数据

    从存储在txt文件中的30000多条数据当中提取自己需要的信息 如下图示例的数据格式 需要提取出now后的数值并存储在另外一个txt文件当中 结果示例 code path r r new data1 txt with open path r
  • C++ 项目

    C 方向 10个企业级别项目 138个工作日 1 学生信息管理系统 C 基础 2 俄罗斯方块 控制台 C 基础
  • Arcgis server在solaris和linux上,用直连的方式连接sde的时的配置

    Arcgis server在solaris和linux上 用直连的方式连接sde的时候需要做一点配置才可以连上 1 在
  • 微信小程序从入坑到放弃二十:生成海报前使用wx.downloadFile或wx.getImageInfo时潜在的坑

    摘要 上周六下午16点左右 公司研发群中扔来一张bug截图 当天21点 群里又扔来bug截图 研发团队二话不说开始查找bug如何复现 22点20分左右 我终于复现了bug 随后就是看源码 搜索 跳坑 爬坑 周日同其他研发小伙伴一样 又是奉献
  • OpenCv案例(九): 基于OpenCvSharp图像分割提取目标区域和定位

    以下原图中 物体连靠在一起 目的是将其分割开 再提取轮廓和定位 原图 最终效果 麻烦的地方是 分割开右下角部分 两个连在一起的目标物体 下图所示 基本方法 BoxFilter滤波 二值化 轮廓提取 凸包检测 图像的矩 代码如下
  • Jar包反编译后修改源码再编译

    Jar包反编译后修改源码再编译 文章目录 Jar包反编译后修改源码再编译 1 场景 2 详细步骤 2 1 查看源码 2 2 生成源文件 2 3 构建项目 2 4 编译成jar包 3 参考链接 1 场景 需要对当前的jar包功能进行修改 但是
  • angularjs系列之轻松使用$q进行异步编程

    angularjs系列之轻松使用 q进行异步编程 来源 网络 编辑 admin 第一部分关于js中的异步编程 异步编程简单的说就是你写了一段代码 但他不会按照你书写代码的顺序立即执行 而是等到程序中发生了某个事件 如用户点击了某个按钮 某个