[Effective JavaScript 笔记]第68条:使用promise模式清洁异步逻辑
构建异步API的一种流行的替代方式是使用promise(有时也被称为deferred或future)模式。已经在本章讨论过的异步API使用回调函数作为参数。
downloadAsync('file.txt',function(file){
console.log('file:'+file);
});
基于promise的API不接收回调函数作为参数。相反,它返回一个promise对象,该对象通过其自身的then方法接收回调函数。
var p=downloadP('file.txt');
p.then(function(file){
console.log('file: '+file);
});
这里看不出与原先的版本有什么不同。但是promise的力量在于它们的组合性。传递给then方法的回调函数不仅产生影响,也可以产生结果。通过回调函数返回一个值,可以构造一个新的promise。
var fileP=downloadP('file.txt');
var lengthP=fileP.then(function(file){
return file.length;
});
lengthP.then(function(length){
console.log('length: '+length);
});
理解promise的一种方法是将它理解为表示最终值的对象。它封装了一个还未完成的并发操作,但最终会产生一个结果值。then方法允许我们提供一个代表最终值的一种类型的promise对象,并产生一个新的promise对象来代表最终值的另一种类型,而不管回调函数返回了什么。
从现有的promise中构造新promise的能力带来了很大的灵活性,并且具有一些简单但强大的惯用法。例如,构造一个实用程序来拼接多个promise的结果。
var filesP=join(downloadP('file1.txt'),
downloadP('file2.txt'),
downloadP('file3.txt'));
filesP.then(function(files){
console.log('file1:'+files[0]);
console.log('file2:'+files[1]);
console.log('file3:'+files[2]);
});
promise库也经常提供一个叫做when的工具函数,其使用类似。
var fileP1=downloadP('file1.txt'),
fileP2=downloadP('file2.txt'),
fileP3=downloadP('file3.txt');
when([fileP1,fileP2,fileP3],function(files){
console.log('file1:'+files[0]);
console.log('file2:'+files[1]);
console.log('file3:'+files[2]);
});
使promise成为卓越的抽象层级的部分原因是通过then方法的返回值来联系结果,或者通过工具函数如join来构成promise,而不是在并行的回调函数间共享数据结构。本质上是安全的,因为避免了66条中讨论过的数据竞争。即使最小心谨慎的程序员也可能会在保存异步操作的结果到共享的变量或数据结构时犯下简单的错误。
var file1,file2;
downloadAsync('file1.txt',function(file){
file1=file;
});
downloadAsync('file2.txt',function(file){
file1=file;
});
promise避免这种BUG,简单风格的组合promise避免了修改共享数据。
注意异步逻辑的有序链事实上也可用有序的promise,而不是在62条中展现的笨重的嵌套模式。错误处理会自动地通过promise传播。当你通过promise串联异步操作的集合时,你可以为整个序列提供一个简单的error回调函数,而不是将error回调函数传递给每一步,正如63条中的代码所示。
尽管这样,有时故意创建某些种类的数据竞争是有用的。Promise为些提供了一个很好的机制。例如,一个应用程序可能需要尝试从多个不同的服务器上同时下载同一份文件,而选择最先完成的那个文件。select(或choose)工具函数接收几个promise并产生一个其值是最先完成下载的文件的promise。换句话,几个promise彼此竞争。
var fileP=select(downloadP('http://e1.com/file.txt'),downloadP('http://e2.com/file.txt'),downloadP('http://e3.com/file.txt'));
fileP.then(function(file){
console.log('file: '+file);
});
select函数的另一个用途是提供超时来终止长时间的操作。
var fileP=select(downloadP('http://e1.com/file.txt'),timeoutErrorP(2000));
fileP.then(function(file){
console.log('file: '+file);
},function(error){
console.log('I/O error or timeout: '+error);
});
这里提供error回调函数作为第二个参数给promise的then方法的机制。
提示
promise代表最终值,即并行操作完成时最终产生的结果
使用promise组合不同的并行操作
使用promise模式的API避免数据竞争
在要求有意的竞争条件时使用select(也被称为choose)
扩展阅读
Promise https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise
[Effective JavaScript 笔记]第68条:使用promise模式清洁异步逻辑的更多相关文章
- [Effective JavaScript 笔记] 第4条:原始类型优于封闭对象
js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //&q ...
- [Effective JavaScript 笔记] 第5条:避免对混合类型使用==运算符
“1.0e0”=={valueOf:function(){return true;}} 是值是多少? 这两个完全不同的值使用==运算符是相等的.为什么呢?请看<[Effective JavaSc ...
- [Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码
函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式 ...
- [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法
js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...
- [Effective JavaScript 笔记]第46条:使用数组而不要使用字典来存储有序集合
对象属性无序性 js对象是一个无序属性集合. var obj={}; obj.a=10; obj.b=30; 属性a和属性b并没有谁前谁后之说.for...in循环,先输出哪个属性都有可能.获取和设置 ...
- [Effective JavaScript 笔记]第45条:使用hasOwnProperty方法以避免原型污染
之前的43条,44条讨论了属性的枚举,但都没有彻底地解决属性查找中原型污染的问题.看下面关于字典的一些操作 'zhangsan' in dict; dict.zhangsan; dict.zhangs ...
- [Effective JavaScript 笔记]第67条:绝不要同步地调用异步的回调函数
设想有downloadAsync函数的一种变种,它持有一个缓存(实现为一个Dict)来避免多次下载同一个文件.在文件已经被缓存的情况下,立即调用回调函数是最优选择. var cache=new Dic ...
- [Effective JavaScript 笔记]第66条:使用计数器来执行并行操作
第63条建议使用工具函数downloadAllAsync接收一个URL数组并下载所有文件,结果返回一个存储了文件内容的数组,每个URL对应一个字符串.downloadAllAsync并不只有清理嵌套回 ...
- [Effective JavaScript 笔记]第65条:不要在计算时阻塞事件队列
第61条解释了异步API怎样帮助我们防止一段程序阻塞应用程序的事件队列.使用下面代码,可以很容易使一个应用程序陷入泥潭. while(true){} 而且它并不需要一个无限循环来写一个缓慢的程序.代码 ...
随机推荐
- jquery中prop()方法和attr()方法的区别浅析
官方例举的例子感觉和attr()差不多,也不知道有什么区别,既然有了prop()这个新方法,不可能没用吧,那什么时候该用attr(),什么时候该用prop()呢 jquery1.6中新加了一个方法pr ...
- Jenkins 2.7.3 LTS 发布
更新如下: Stop A/B testing of the remoting JNLP3 protocol due to the known issues. The protocol can be e ...
- HTTP Methods: GET v.s POST
HTTP works as a request-response protocol between a client and server. A web browser may be the clie ...
- css去掉使用bootstrap框架后打印网页时预览效果下的超链接
在我们写网页的时候,超链接是链接各个页面的桥梁,也是搜索引擎爬虫(spider)收录网站页面的关键,因此,在每个网页中会有许多的超链. 今天,一个同行妹妹在使用了bootstrap框架来搭建自己的网站 ...
- 继续畅通工程-Floyd
畅通工程续 Time Limit : 3000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) Total Submiss ...
- sql 数据库 初级 个人学习总结(一)
数据库个人总结(初级)1.增删改查 insert into 表名 values ('条件','条件2') delete from 表名 where 条件 update 表名 set=条件值 where ...
- javascript基础笔记
1.获取元素: var box=document.getElementById("box");2.改变元素内容: b ...
- 代理模式 & Java原生动态代理技术 & CGLib动态代理技术
第一部分.代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常 ...
- IOS彩票第二天设置界面(2)
*********代码的抽取ILBaseTableViewController.h #import <UIKit/UIKit.h> @interface ILBaseTableViewCo ...
- Python的正则表达式笔记
1. "先抓大再抓小": 遇到一个正则表达式无法一次性筛选出所需内容时, 可以先在一个范围内筛选第一次, 再在小范围中筛选第二次. 2. pattern = re.compile( ...