使用 Promises 编写更优雅的 JavaScript 代码
你可能已经无意中听说过 Promises,很多人都在讨论它,使用它,但你不知道为什么它们如此特别。难道你不能使用回调么?有什么了特别的?在本文中,我们一起来看看 Promises 是什么以及如何使用它们写出更优雅的 JavaScript 代码。
Promises 易于阅读
比如说我们想从 HipsterJesus 的API中抓取一些数据并将这些数据添加到我们的页面中。这些 API 的响应数据形式如下:
{
"text": "<p>Lorem ipsum...</p>",
"params": {
"paras": 4,
"type": "hipster-latin"
}}
要使用回调的话,我们通常要写如下形式的东西:
$.getJSON('http://hipsterjesus.com/api/', function(data) {
$('body').append(data.text);
});
如果你有 jQuery 的使用经历,你会认出我们创建了一个 GET 请求并且希望响应内容是 JSON。我们还传递了一个回调函数来接受响应的 JSON,以将数据添加到文档中。
另外一种书写方法是使用 getJSON 方法返回的 promise 对象。你可以直接在这个返回对象上绑定一个回调。
var promise = $.getJSON('http://hipsterjesus.com/api/');promise.done(function(data) {
$('body').append(data.text);
});
在上面的回调例子中,当响应成功时它将 API 请求的结果添加到文档中。但当响应失败是会发生什么呢?我们可以在我们的 promise 上绑定一个失败处理器。
var promise = $.getJSON('http://hipsterjesus.com/api/');promise.done(function(data) {
$('body').append(data.text);});promise.fail(function() {
$('body').append('<p>Oh no, something went wrong!</p>');
});
大多数人删掉了 promise 变量,这样更简洁,一眼就能看出代码的作用。
$.getJSON('http://hipsterjesus.com/api/').done(function(data) {
$('body').append(data.text);}).fail(function() {
$('body').append('<p>Oh no, something went wrong!</p>');
});
jQuery 也包含一个一直发生的事件处理器,不论请求成功失败都会被调用。
$.getJSON('http://hipsterjesus.com/api/').done(function(data) {
$('body').append(data.text);}).fail(function() {
$('body').append('<p>Oh no, something went wrong!</p>');}).always(function() {
$('body').append('<p>I promise this will always be added!.</p>');
});
通过使用promise,回调的顺序是按预期的。我们能确保正常回调先被调用,然后是失败回调,最后是一直发生的回调。
更好的 API
比如说我们想创造一个 HipsterJesus API 的封装对象。我们会添加一个方法——html,它将来自 API 的 HTML 数据返回。与之前设置一个回调处理器来解析请求不同,我们可以让方法返回一个 promise 对象。
var hipsterJesus = {
html: function() {
return $.getJSON('http://hipsterjesus.com/api/').then(function(data) {
return data.text;
});
}};
这个做法很酷,这样我们可以绕过 promise 对象而不必担心何时或如何解析它的值。任何需要 promise 返回值的代码只需注册一个成功响应回调即可。
then方法允许我们修改promise的结果并将其传递给链中的下一个处理器。这意味现在我们可以这样使用新的API:
hipsterJesus.html().done(function(html) {
$("body").append(html);
});
直到最近,AngularJS 出现了一个杀手级特性,模板可以直接绑定到promise。在Angular的控制器中,像这样:
$scope.hipsterIpsum = $http.get('http://hipsterjesus.com/api/');
这样,在模板中写 {{ hipsterIpsum.text }} 就很简单了。当 promise 解析后,Angular 不需要自动更新视图。不幸的是 Angular 团队已经放弃了这一特性。现在,它可以通过调用 $parseProvider.unwrapPromises(true) 来启用。我希望Angular已经其他框架一直包含此特性(我会一直留意)。
链式调用
Promise 最出彩的部分是你可以将它们串联起来。比如说我们想添加一个方法到一个返回一段数组的 API。
var hipsterJesus = {
html: function() {
return $.getJSON('http://hipsterjesus.com/api/').then(function(data) {
return data.text;
});
},
paragraphs: function() {
return this.html().then(function(html) {
return html.replace(/<[^>]+>/g, "").split("");
});
}};
我们以上面的方式这种 HTML 方法,我们用它在 paragraphs 方法中。因为promise回调函数的返回值将传递给链中的下一个回调,我们能够在通过它们时自由地创建小的、功能性的方法来改变数据。
我们可以按需求任意次串联promise。让我们添加一个。
var hipsterJesus = {
html: function() {
return $.getJSON('http://hipsterjesus.com/api/').then(function(data) {
return data.text;
});
},
paragraphs: function() {
return this.html().then(function(html) {
return html.replace(/<[^>]+>/g, "").split("");
});
},
sentences: function() {
return this.paragraphs().then(function(paragraphs) {
return [].concat.apply([], paragraphs.map(function(paragraph) {
return paragraph.split(/. /);
}));
});
}};
多个调用
可能 promise 最显著的特点是调用多个 API 的能力。当使用回调时,如果你需要同时创建两个API调用时会发生什么呢?你可能会这样写:
var firstData = null;var secondData = null;var responseCallback = function() {
if (!firstData || !secondData)
return;
// do something}$.get("http://example.com/first", function(data) {
firstData = data;
responseCallback();});$.get("http://example.com/second", function(data) {
secondData = data;
responseCallback();
});
使用 promise 的话,这就简单多了:
var firstPromise = $.get("http://example.com/first");
var secondPromise = $.get("http://example.com/second");
$.when(firstPromise, secondPromise).done(function(firstData, secondData) {
// do something
});
这里我们使用 when 方法,将其绑定到一个供两个请求都完成时调用的处理器上。
结论
这就是 Promise。希望你马上就想到一些可以用 Promise 实现的的可怕的事情。你最喜欢使用它们的方式是什么?在评论中告诉我吧!
*注:为简单起见,本文使用了jQuery的延期执行。jQuery 的 Deferred对象 和 Promises/A+的规范 间有细微的差别,这个规范更标准。更多信息,查看 jQuery维基 上的问答。
您可能感兴趣的相关文章
译文链接:使用 Promises 模式编写更好的 JavaScript 代码
编译来源:梦想天空 ◆ 关注前端开发技术 ◆ 分享网页设计资源
本文来自【梦想天空(http://www.cnblogs.com/lhb25/)】
使用 Promises 编写更优雅的 JavaScript 代码的更多相关文章
- 如何写出优雅的JavaScript代码 ? && 注释
如何写出优雅的JavaScript代码 ? 之前总结过一篇<如何写出优雅的css代码?>, 但是前一段时间发现自己的js代码写的真的很任性,没有任何的优雅可言,于是这里总结以下写js时应当 ...
- 编写可测试的JavaScript代码
<编写可测试的JavaScript代码>基本信息作者: [美] Mark Ethan Trostler 托斯勒 著 译者: 徐涛出版社:人民邮电出版社ISBN:9787115373373上 ...
- [label][翻译][JavaScript-Translation]七个步骤让你写出更好的JavaScript代码
7 steps to better JavaScript 原文链接: http://www.creativebloq.com/netmag/7-steps-better-javascript-5141 ...
- 编写可维护的JavaScript代码(部分)
平时使用的时VS来进行代码的书写,VS会自动的将代码格式化,所有写了这么久的JS代码,也没有注意到这些点.看了<编写可维护的javascript代码>之后,做了些笔记. var resul ...
- 使用AmplifyJS和JQuery编写更好更优雅的javascript事件处理代码
事件(或消息)是一种经常使用的软件设计模式.可以减少消息处理者和消息公布者的之间的耦合,比方J2EE里面的JMS规范.设计模式中的观察者模式(也叫公布/订阅模式).这对于javascript代码相同适 ...
- 新书《编写可测试的JavaScript代码 》出版,感谢支持
本书介绍 JavaScript专业开发人员必须具备的一个技能是能够编写可测试的代码.不管是创建新应用程序,还是重写遗留代码,本书都将向你展示如何为客户端和服务器编写和维护可测试的JavaScript代 ...
- 编写更好的jQuery代码
这是一篇关于jQuery的文章,写到这里给初学者一些建议. 现在已经有很多文章讨论jQuery和JavaScript的性能问题,然而,在这篇文章中我计划总结一些提升速度的技巧和一些我自己的建议来改善你 ...
- 编写更好的jQuery代码的建议
讨论jQuery和javascript性能的文章并不罕见.然而,本文我计划总结一些速度方面的技巧和我本人的一些建议,来提升你的jQuery和javascript代码.好的代码会带来速度的提升.快速渲染 ...
- 编写更好的C#代码
引言 开发人员总是喜欢就编码规范进行争论,但更重要的是如何能够在项目中自始至终地遵循编码规范,以保证项目代码的一致性.并且团队中的所有人都需要明确编码规范所起到的作用.在这篇文章中,我会介绍一些在我多 ...
随机推荐
- CSS裁剪clip
× 目录 [1]定义 [2]RECT [3]应用 前面的话 CSS裁剪clip这个属性平时用的不多,但其实它并不是CSS3的新属性,很早就开始出现了.本文将介绍关于clip属性的相关知识 定义 一个绝 ...
- 使用 CSS3 制作一组超时尚的动画按钮效果
通过 CSS3 的新特性,我们创作出好的交互和效果的可能性大大增加.这篇文章中,我想与大家分享一些 CSS3 动画按钮效果.我们的想法是创建一个具有不同风格的一些动画链接元素,鼠标悬停时有动画效果和活 ...
- 响应式网页中,如何只用CSS实现div的高和宽保持固定比例
引言: 如果div里是<img>,原生就支持. .item img { float: left; margin:5%; width: 20%; } >> ...
- Visual Studio 2010 起始页中 不显示最近使用的项目问题,解决办法
最近新装了vs2010,发现打开vs2010 后 起始页面中的最近使用的栏目中 并未显示最近加载的项目 解决办法如下: 运行 regedit 打开下面的键值: HKEY_CURRENT_USER/So ...
- redis学习教程之一基本命令
参阅redis中文的 互动教程(interactive tutorial)来学习的. 目录: 全局操作 get get incr 自增 del 删除 expire 定时 list 队列 set ...
- html/css基础篇——DOM中关于脱离文档流的几种情况分析
所谓的文档流,指的是元素排版布局过程中,元素会自动从左往右,从上往下的流式排列.并最终窗体自上而下分成一行行, 并在每行中按从左至右的顺序排放元素.脱离文档流即是元素打乱了这个排列,或是从排版中拿走. ...
- CompressHelper
public static string CompressString(string unCompressedString) { byte[] bytData = System.Text.Encodi ...
- [译]学习IPython进行交互式计算和数据可视化(三)
第二章 在本章中,我们将详细学习IPython相对以Python控制台带来的多种改进.特别的,我们将会进行下面的几个任务: 从IPython中使用系统shell以在shell和Python之间进行强大 ...
- 常用的 SQL语句------CRUD
复习之前课本上的sql语句,以前上课的时候都是老师在上面讲,我们在下面玩,根本没有把这个放在心上,等到考试的时候临时学习突击下,就可以顺利过60了,但是现在不行了,自己要重新的学习sql,应该把里面最 ...
- Winform如何实现ComboBox模糊查询
最近朋友问了一个关于Winform实现ComboBox模糊查询的知识点,自己好久没有搞Winform了,就上手练了一下,废话不多说,进入正题. 前台设计: 前台就是一个简单的Form窗体+一个Comb ...