如何利用Promises编写更优雅的JavaScript代码_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+的规范 间有细微的差别,这个规范更标准。

以上这篇如何利用Promises编写更优雅的JavaScript代码就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索javascript
promises
javascript promises、javascript编写工具、编写javascript的工具、编写javascript的软件、javascript编写计算器,以便于您获取更多的相关知识。

时间: 2024-08-17 20:08:06

如何利用Promises编写更优雅的JavaScript代码_javascript技巧的相关文章

使用CoffeeScrip优美方式编写javascript代码_javascript技巧

JavaScript无疑是在web最伟大的发明之一,几乎一切网页动态效果都是基于它丰富的计算能力.而且它的能力在各种新的JavaScript的Engine下也越来越强了,比如Google Chrome用的V8 Engine. 但是由于诞生的太早,有很多语法定义在今天看来有些效率低下了,一些更加先进的语法形式,由于历史原因,没办法加入到现在的JavaScript语言中,可以说一种遗憾. 世界上的很多天才都在为构建更好的JavaScript而努力.已经有了很多尝试,其中最有前途的,无非就是Coffe

实现变速回到顶部的JavaScript代码_javascript技巧

随着近几年来 JavaScript 的应用日渐广泛, 滑动效果无处不在, 于是我也跟跟风, 将置顶功能做成了滑动效果. 后来为了更贴合物理特征, 改造做成了减速的滑动效果. 首先说一下原理吧. 我们会获取滚动条到页面顶部的距离, 然后上移一定的距离; 再获取滚动条到页面顶部的距离, 上移一定的距离 (比上一次小一点); ... JavaScript 代码: 复制代码 代码如下: /** * 回到页面顶部 * @param acceleration 加速度 * @param time 时间间隔 (

自动最大化窗口的Javascript代码_javascript技巧

自动最大化窗口的Javascript代码 大家看看这个最大化窗口的效果如何?在 <body> 与 </body> 之间加入: 复制代码 代码如下: <SCRIPT language="javascript"> setTimeout('top.moveTo(0,0)',5000); setTimeout('top.resizeTo(screen.availWidth,screen.availHeight)',5000); </script>

动态创建按钮的JavaScript代码_javascript技巧

废话不多说了,直接给大家贴js代码了,具体代码如下所示: <!doctype html> <html> <head> <meta charset="UTF-8" /> <title>Document</title> <script type="text/javascript"> var i = 0; function addInput(){ var o = document.crea

javascript利用初始化数据装配模版的实现代码_javascript技巧

var list = [{id:1, name:"czone", age:21}, {id:2, name:'czonechan', age:21}]; var template ='<div id="p$id"><span class="name">$name</span><span class="age">$age</span></div>'; 实现一

JavaScript下利用fso判断文件是否存在的代码_javascript技巧

复制代码 代码如下: function ReportFileStatus(filespec) { var fso, s = filespec; fso = new ActiveXObject("Scripting.FileSystemObject"); if (fso.FileExists(filespec)) s += " exists."; else s += " doesn't exist."; return(s); } 采用客户端的 Fi

实例:尽可能写友好的Javascript代码_javascript技巧

在Search Engine的robot搜索时,针对的type,text/html此类"文本"的友好度是最高的(现阶段text/xml除外),而text/javascript此类的友好度不理想,如果robot还要判断DHTML代码的话,那这个复杂度也是较高,而且划不来,因此,在DHTML编程时,如果要提升代码的友好度.采用的方法,较好的方法是"尽可能是把DHTML的代码简化成没有HTML的代码".这句话如何理解? e.g:  一个javascript menu. 

利用Keydown事件阻止用户输入实现代码_javascript技巧

先了解下各事件的区别 KeyDown:在控件有焦点的情况下按下键时发生 KeyPress:在控件有焦点的情况下按下键时发生 KeyUp: 在控件有焦点的情况下释放键时发生 1.KeyPress主要用来接收字母.数字等ANSI字符.KeyDown 和 KeyUP 事件过程通常可以捕获键盘除了PrScrn所有按键(这里不讨论特殊键盘的特殊键 2.KeyPress 只能捕获单个字符,KeyDown 和KeyUp 可以捕获组合键. 3.KeyPress 不显示键盘的物理状态(SHIFT键),而只是传递一

实现网页内容水平或垂直滚动的Javascript代码_javascript技巧

主要两个部分,一.是滚动内容部分:二.JS的滚动代码部分,也只有两句话. 一.传统的滚动代码 用Javascript实现新闻内容的水平滚动! [Ctrl+A 全选 注:如需引入外部Js需刷新才能执行] 传统的滚动代码应用效果比较单一,而且经常还存在浏览器的兼容性问题,比如在FIREFOX上效果就会出现marquee的特效无效的问题. 二.Javascript实现的滚动效果 用Javascript实现新闻内容的水平滚动1 //div标签中的宽度width等参数可以自行调节 [Ctrl+A 全选 注