如何利用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+的规范 间有细微的差别,这个规范更标准。

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

(0)

相关推荐

  • 基于promise.js实现nodejs的promises库

    今天从GIT源码库中下载了promise.js,发现该源码是基于Web前端JavaScript写的,并不能直接用于nodejs.还好代码不是很多,也不是很复杂.经过分析整合,将其实现为nodejs的一个框架,代码如下: (function(){ /** * Copyright 2012-2013 (c) Pierre Duquesne <stackp@online.fr> * script: promise.js * description: promises的nodejs模块 * modif

  • 详解Javacript和AngularJS中的Promises

    比如页面调用google地图的api时就使用到了promise. function success(position){ var cords = position.coords; console.log(coords.latitude + coords.longitude); } function error(err){ console.warn(err.code+err.message) } navigator.geolocation.getCurrentPosition(success, e

  • Javascript中的异步编程规范Promises/A详细介绍

    Javascript里异步编程逐渐被大家接受,先前大家一般通过回调嵌套,setTimeout.setInterval等方式实现,代码看起来非常不直观,不看整个代码逻辑很难快速理解.Javascript里异步函数大概有I/O函数(Ajax.postMessage.img load.script load等).计时函数(setTimeout.setInterval)等. 这些我们都很熟悉,在复杂的应用中往往会嵌套多层,甚至以为某些步骤未完成而导致程序异常,最简单的例子:比如你往DOM中注入节点,你必

  • 如何利用Promises编写更优雅的JavaScript代码

    你可能已经无意中听说过 Promises,很多人都在讨论它,使用它,但你不知道为什么它们如此特别.难道你不能使用回调么?有什么了特别的?在本文中,我们一起来看看 Promises 是什么以及如何使用它们写出更优雅的 JavaScript 代码. Promises 易于阅读 比如说我们想从 HipsterJesus 的API中抓取一些数据并将这些数据添加到我们的页面中.这些 API 的响应数据形式如下: { "text": "<p>Lorem ipsum...<

  • 利用函数的惰性载入提高javascript代码执行效率

    在 javascript 代码中,因为各浏览器之间的行为的差异,我们经常会在函数中包含了大量的 if 语句,以检查浏览器特性,解决不同浏览器的兼容问题. 例如,我们最常见的为 dom 节点添加事件的函数: 复制代码 代码如下: function addEvent (type, element, fun) { if (element.addEventListener) { element.addEventListener(type, fun, false); } else if(element.a

  • 通过实践编写优雅的JavaScript代码

    有没有似曾相识 如果你对于代码,除了关注是否能准确的执行业务逻辑,还关心代码本身是怎么写的,是否易读,那么你应该会关注如何写出干净优雅的代码.作为专业的工程师,除了保证自己的代码没有bug,能正确的完成业务逻辑,还应该保证几个月后的自己,或者其他工程师,也能够维护自己的代码.你写的每一段代码,通常情况下,都不会是 一次性 工作,通常伴随着后续的不断迭代.如果代码不够优雅,那么将来维护这段代码的人(甚至你自己),都将感到非常痛苦.祈祷吧,将来面对这些糟糕代码的人,不是你自己,而是别人. OK,我们

  • 编写更好的JavaScript条件式和匹配条件的技巧(小结)

    介绍 如果你像我一样乐于见到整洁的代码,那么你会尽可能地减少代码中的条件语句.通常情况下,面向对象编程让我们得以避免条件式,并代之以继承和多态.我认为我们应当尽可能地遵循这些原则. 正如我在另一篇文章 JavaScript 整洁代码的最佳实践里提到的,你写的代码不单单是给机器看的,还是给"未来的自己"以及"其他人"看的. 从另一方面来说,由于各式各样的原因,可能我们的代码最终还是会有条件式.也许是修复 bug 的时间很紧,也许是不使用条件语句会对我们的代码库造成大的

  • 使用AngularJS编写较为优美的JavaScript代码指南

    本文示例代码下载:modulePattern.zip - 所有的 4 个 HTML 文件  以及 panacea.js - 1.6 KB 介绍 AngularJS 的库里面有很多东西,但本文中我只想专注于小的,针对特定主题的库,我相信通过它们能对Angular有一个较好的介绍.  理解这篇文章并不需要你有任何Angular相关的,甚至是JavaScript的经验.希望你能从本文中看到一些使用Angular的好处,并乐于动手尝试. 背景 我使用Angular有一段时间了,而在学习Angular的时

  • 编写跨浏览器的javascript代码必备[js多浏览器兼容写法]

    序号 操作 分类 IE(6.0) FireFox(2.0) Mozilla(1.5) 当前浏览器 备注 1 "." 访问tag的固有属性 OK OK OK OK 2 "." 访问tag的用户定义属性eg: <input type="checkbox" myattr="test"> OK NO NO OK 可以用getAttribute函数 替代 3 obj.getAttribute 访问tag的固有属性 OK OK

  • 如何利用JavaScript编写更好的条件语句详解

    前言 在任何编程语言中,代码需要根据不同的条件在给定的输入中做不同的决定和执行相应的动作. 例如,在一个游戏中,如果玩家生命点为0,游戏结束.在天气应用中,如果在早上被查看,显示一个日出图片,如果是晚上,则显示星星和月亮.在这篇文章中,我们将探索JavaScript中所谓的条件语句如何工作. 如果你使用JavaScript工作,你将写很多包含条件调用的代码.条件调用可能初学很简单,但是还有比写一对对if/else更多的东西.这里有些编写更好更清晰的条件代码的有用提示. 1. 数组方法 Array

  • 基于Day.js更优雅的处理JavaScript中的日期

    目录 为什么使用day.js Moment.js Day.js 没有day.js我们怎么办 Day.js 例子 1. 获取两个日期相差的天数 2. 检查日期是否合法 3. 获取输入日期月份的天数 4. 添加日.月.年.时.分.秒 5. 减去日.月.年.时.分.秒 使用插件来扩展功能 1. RelativeTime 2. WeekOfYear 3. IsSameOrAfter 4. MinMax 5. IsBetween 今天我推荐给大家一个库 Day.js,它能够帮助我们处理JavaScript

  • JavaScript中async await更优雅的错误处理方式

    目录 背景 为什么要错误处理 async await 更优雅的错误处理 小结 总结 背景 团队来了新的小伙伴,发现我们的团队代码规范中,要给 async  await 添加 try...catch.他感觉很疑惑,假如有很多个(不集中),那不是要加很多个地方?那不是很不优雅? 为什么要错误处理 JavaScript 是一个单线程的语言,假如不加 try ...catch ,会导致直接报错无法继续执行.当然不意味着你代码中一定要用 try...catch 包住,使用 try...catch 意味着你

  • JavaScript代码优雅,简洁的编写技巧总结

    1. 强类型检查 用===代替 == // 如果处理不当,它会极大地影响程序逻辑.这就像,你想向左走,但由于某种原因,你向右走 0 == false // true 0 === false // false 2 == "2" // true 2 === "2" // false // 例子 const value = "500"; if (value === 500) { console.log(value); // 条件不成立,不会进入 } i

随机推荐