使用 Promises 编写更优雅的 JavaScript 代码

简介:   你可能已经无意中听说过 Promises,很多人都在讨论它,使用它,但你不知道为什么它们如此特别。难道你不能使用回调么?有什么了特别的?在本文中,我们一起来看看 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/)】

作者:山边小溪
主站:yyyweb.com 记住啦:)
欢迎任何形式的转载,但请务必注明出处。

相关文章
|
8天前
|
JSON JavaScript 前端开发
JavaScript原生代码处理JSON的一些高频次方法合集
JavaScript原生代码处理JSON的一些高频次方法合集
|
28天前
|
存储 JavaScript 前端开发
非常实用的JavaScript一行代码(整理总结)
非常实用的JavaScript一行代码(整理总结)
27 0
|
1月前
|
JavaScript 前端开发 测试技术
如何编写JavaScript模块化代码
如何编写JavaScript模块化代码
12 0
|
1月前
|
机器学习/深度学习 前端开发 JavaScript
实用的javascript代码分享
32个史上最有用的js代码
28 1
|
2月前
|
JavaScript 前端开发 算法
Node.js 艺术:用代码打印出绚丽多彩的控制台柱状图
Node.js 艺术:用代码打印出绚丽多彩的控制台柱状图
40 0
|
2月前
|
JSON 前端开发 JavaScript
JavaScript黑科技:简洁有用的一行代码,让你的开发效率飙升!
JavaScript黑科技:简洁有用的一行代码,让你的开发效率飙升!
63 0
|
2月前
|
前端开发 JavaScript 安全
从前端性能优化角度谈JavaScript代码压缩与混淆
本文从前端性能优化的角度出发,探讨了JavaScript代码压缩与混淆的重要性及实现方式,通过分析不同压缩混淆工具的特点和效果,为开发者提供了实用的指导和建议。
|
23天前
|
JSON 前端开发 JavaScript
16个重要的JavaScript代码
16个重要的JavaScript代码
30 1
|
25天前
|
JavaScript
当当网新用户注册界面——JS代码
当当网新用户注册界面——JS代码
7 0
|
25天前
|
JavaScript
当当网首页——JS代码
当当网首页——JS代码
8 1