Promise API 简介

译者注: 到处是回调函数,代码非常臃肿难看, Promise 主要用来解决这种编程方式, 将某些代码封装于内部。

Promise 直译为“承诺”,但一般直接称为 Promise;

代码的可读性非常重要,因为开发人员支出一般比计算机硬件的支出要大很多倍。

虽然同步代码更容易跟踪和调试, 但异步方式却具有更好的性能与灵活性.
怎样在同一时刻发起多个请求, 然后分别处理响应结果? Promise 现已成为 JavaScript 中非常重要的一个组成部分, 很多新的API都以 promise 的方式来实现。下面简要介绍 promise, 以及相应的 API 和使用示例!

Promises 周边

XMLHttpRequest 是异步API, 但不算 Promise 方式。当前使用 Promise 的原生 api 包括:

  • Battery API
  • fetch API (用来替代 XHR)
  • ServiceWorker API (参见后期文章!)

Promise 会越来越流行,所以前端开发需要快速掌握它们。当然, Node.js 是另一个使用 Promise 的平台(显然, Promise 在Node中是一个核心特性)。

测试 promises 可能比你想象的还要容易, 因为 setTimeout 可以用来当作异步“任务”!

Promise 基本用法

直接使用 new Promise() 构造函数的方式, 应该只用来处理遗留的异步任务编程, 例如 setTimeout 或者 XMLHttpRequest。 通过 new 关键字创建一个新的 Promise 对象, 该对象有 resolve(搞定!) 和 reject(拒绝!) 两个回调函数:

var p = new Promise(function(resolve, reject) {// ... ... // 此处,可以执行某些异步任务,然后...// 在回调中,或者任何地方执行 resolve/rejectif(/* good condition */) {resolve('传入成果结果信息,如 data');}else {reject('失败:原因...!');}
});p.then(function(data) { /* do something with the result */
}).catch(function(err) {/* error :( */
});

一般是由开发人员根据异步任务执行的结果,来手动调用 resolve 或者 reject. 一个典型的例子是将 XMLHttpRequest 转换为基于Promise的任务:

// 本段示例代码来源于 Jake Archibald's Promises and Back:
// http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promisifying-xmlhttprequestfunction get(url) {// 返回一个 promise 对象.return new Promise(function(resolve, reject) {// 执行常规的 XHR 请求var req = new XMLHttpRequest();req.open('GET', url);req.onload = function() {// This is called even on 404 etc// so check the statusif (req.status == 200) {// Resolve the promise with the response textresolve(req.response);}else {// Otherwise reject with the status text// which will hopefully be a meaningful errorreject(Error(req.statusText));}};// Handle network errorsreq.onerror = function() {reject(Error("网络出错"));};// Make the requestreq.send();});
};// 使用!
get('story.json').then(function(response) {console.log("Success!", response);
}, function(error) {console.error("Failed!", error);
});

有时候在 promise 方法体中不需要执行异步任务 —— 当然,在有可能会执行异步任务的情况下, 返回 promise 将是最好的方式, 这样只需要给定结果处理函数就行。在这种情况下, 不需要使用 new 关键字, 直接返回 Promise.resolve() 或者 Promise.reject()即可。例如:

var userCache = {};function getUserDetail(username) {// In both cases, cached or not, a promise will be returnedif (userCache[username]) {// Return a promise without the "new" keywordreturn Promise.resolve(userCache[username]);}// Use the fetch API to get the information// fetch returns a promisereturn fetch('users/' + username + '.json').then(function(result) {userCache[username] = result;return result;}).catch(function() {throw new Error('Could not find user: ' + username);});
};

因为总是会返回 promise, 所以只需要通过 thencatch 方法处理结果即可!

then

每个 promise 实例都有 then 方法, 用来处理执行结果。 第一个 then 方法回调的参数, 就是 resolve() 传入的那个值:

new Promise(function(resolve, reject) {// 通过 setTimeout 模拟异步任务setTimeout(function() { resolve(10); }, 3000);
})
.then(function(result) {console.log(result);
});// console 输出的结果:
// 10

then 回调由 promise 的 resolved 触发。你也可以使用链式的 then` 回调方法:

new Promise(function(resolve, reject) { // 通过 setTimeout 模拟异步任务setTimeout(function() { resolve(10); }, 3000);
})
.then(function(num) { console.log('first then: ', num); return num * 2; })
.then(function(num) { console.log('second then: ', num); return num * 2; })
.then(function(num) { console.log('last then: ', num);});// console 输出的结果:
// first then:  10
// second then:  20
// last then:  40

每个 then 收到的结果都是之前那个 then 返回的值。

如果 promise 已经 resolved, 但之后才调用 then 方法, 则立即触发回调。如果promise被拒绝之后才调用 then, 则回调函数不会被触发。

catch

当 promise 被拒绝时, catch 回调就会被执行:

new Promise(function(resolve, reject) {// 通过 setTimeout 模拟异步任务setTimeout(function() { reject('Done!'); }, 3000);
})
.then(function(e) { console.log('done', e); })
.catch(function(e) { console.log('catch: ', e); });// console 输出的结果:
// 'catch: Done!'

传入 reject 方法的参数由你自己决定。一般来说是传入一个 Error 对象:

reject(Error('Data could not be found'));

Promise.all

想想JavaScript加载器的情形: 有时候会触发多个异步交互, 但只在所有请求完成之后才会做出响应。—— 这种情况可以使用 Promise.all 来处理。Promise.all 方法接受一个 promise 数组, 在所有 promises 都搞定之后, 触发一个回调:

Promise.all([promise1, promise2]).then(function(results) {// Both promises resolved
})
.catch(function(error) {// One or more promises was rejected
});

Promise.all 的最佳示例是通过fetch同时发起多个 AJAX请求时:

var request1 = fetch('/users.json');
var request2 = fetch('/articles.json');Promise.all([request1, request2]).then(function(results) {// Both promises done!
});

你也可以组合使用 fetch 和 Battery 之类的 API ,因为他们都返回 promises:

Promise.all([fetch('/users.json'), navigator.getBattery()]).then(function(results) {// Both promises done!
});

当然, 处理拒绝的情况比较复杂。如果某个 promise 被拒绝, 则 catch 将会被第一个拒绝(rejection)所触发:

var req1 = new Promise(function(resolve, reject) { // 通过 setTimeout 模拟异步任务setTimeout(function() { resolve('First!'); }, 4000);
});
var req2 = new Promise(function(resolve, reject) { // 通过 setTimeout 模拟异步任务setTimeout(function() { reject('Second!'); }, 3000);
});
Promise.all([req1, req2]).then(function(results) {console.log('Then: ', one);
}).catch(function(err) {console.log('Catch: ', err);
});// From the console:
// Catch: Second!

随着越来越多的 API 支持 promise, Promise.all 将会变得超级有用。

Promise.race

Promise.race 是一个有趣的函数. 与 Promise.all 相反, 只要某个 priomise 被 resolved 或者 rejected, 就会触发 Promise.race:

var req1 = new Promise(function(resolve, reject) { // 通过 setTimeout 模拟异步任务setTimeout(function() { resolve('First!'); }, 8000);
});
var req2 = new Promise(function(resolve, reject) { // 通过 setTimeout 模拟异步任务setTimeout(function() { resolve('Second!'); }, 3000);
});
Promise.race([req1, req2]).then(function(one) {console.log('Then: ', one);
}).catch(function(one, two) {console.log('Catch: ', one);
});// From the console:
// Then: Second!

一个案例是请求的资源有 主站资源和备用资源(以防某个不可用)。

改变习惯, 使用 Promise

在过去几年中 Promise 一直是个热门话题(如果你是 Dojo Toolkit 用户,那么就是已经有10年了), 已经从一个JavaScript框架变成了语言的一个主要成分. 很快你就会看到大多数新的 JavaScript api 都会基于 Promise 的方式来实现……

… 当然这是一件好事! 开发人员能够避开回调的地狱, 异步交互也可以像其他变量一样传递. Promise 还需要一段时间来普及, 现在是时候去学习他们了!

本文转载自:众成翻译
译者:铁胖子
链接:http://www.zcfy.cc/article/351
原文:https://davidwalsh.name/promises

Promise API 简介相关推荐

  1. 线程编程常见API简介(中)

    2019独角兽企业重金招聘Python工程师标准>>> 一.概述 在<线程编程常见API简介(上) >中讲述了有关线程创建过程中常用的 API 的使用方法,本节继续讲述有 ...

  2. WebSocket API简介

    WebSocket是html5新增加的一种通信协议,目前流行的浏览器都支持这个协议,例如Chrome,Safari,Firefox,Opera,IE等等,对该协议支持最早的应该是chrome,从chr ...

  3. web API简介(二):客户端储存之document.cookie API

    概述 前篇:web API简介(一):API,Ajax和Fetch 客户端储存从某一方面来说和动态网站差不多.动态网站是用服务端来储存数据,而客户端储存是用客户端来储存数据.document.cook ...

  4. 【Netty】NIO 网络通信 SelectionKey 常用 API 简介

    文章目录 I . SelectionKey 简介 II . SelectionKey 事件简介 III . SelectionKey 常用 API 简介 I . SelectionKey 简介 1 . ...

  5. 【Java 网络编程】TCP API 简介 ( Socket | ServerSocket )

    文章目录 I Socket API 简介 II ServerSocket API 简介 III Socket 数据交互 IV Socket 客户端操作流程 V Socket 服务器端操作流程 VI S ...

  6. java编译器使用教程_Java编译器API简介

    今天给大家分享的是Java编译器API简介,文章部分内容摘自[优锐课]学习笔记. Java编译器API Java编译器API是Java模块(称为java.compiler)的一部分.该模块包括语言模型 ...

  7. html5画电池状态,HTML5的一个显示电池状态的API简介

    这篇文章主要介绍了HTML5的一个显示电池状态的API简介,由Mozilla设计,具体的设备和浏览器支持情况还要通过检测才能确定,需要的朋友可以参考下 移动设备的份额在网络流量中在大量增长,其所贡献的 ...

  8. ZABBIX API简介及使用

    API简介 Zabbix API开始扮演着越来越重要的角色,尤其是在集成第三方软件和自动化日常任务时.很难想象管理数千台服务器而没有自动化是多么的困难.Zabbix API为批量操作.第三方软件集成以 ...

  9. 基于阿里云的API简介

    基于阿里云的API简介 API简介 如果您熟悉网络服务协议和一种以上编程语言,推荐您调用API管理您的云上资源和开发自己的应用程序. 使用说明 ECS API支持HTTP或者HTTPS网络请求协议,允 ...

最新文章

  1. ORA-01855: AM/A.M. or PM/P.M. required错误解决
  2. Nginx使用webbench进行压力测试
  3. 《系统集成项目管理工程师》必背100个知识点-58沟通方式
  4. linux中查找某一个字符串,Linux系统下,在文件中查找某个字符串
  5. python分组函数_Python中如何按列分组和按自己的函数汇总
  6. python无条件跳转_python按按钮实现界面跳转_python实现界面跳转 - CSDN
  7. 爬取人民日报_【爬虫系列】人民日报半个世纪的资料(文末福利)
  8. ASP.NET MVC+LINQ开发一个图书销售站点(6):创建数据层
  9. 滴滴回应高额抽成:确实存在;抖音火山版被判赔腾讯 800 万元;华为鸿蒙系统有望下月规模化推送|极客头条...
  10. Leetcode 129. 根到叶子结点数字之和
  11. java this()函数_Java经典面试题之(如何正确的使用this?)
  12. 物联网单片机毕业设计实现
  13. php date 函数用法,PHP日期时间函数date()使用方法
  14. 23种PHP开发工具集合
  15. jquery获取ip地址
  16. Linux的系统安全及管理
  17. QML:ListView按下选中当前项和高亮的一例
  18. 【PowerQuery】Excel 自动刷新PowerQuery连接
  19. Calendar 日历
  20. 数据读取机制Dataloader和Dataset和Transforms

热门文章

  1. 处理Linux中大量ESTABLISHED进程
  2. Ubuntu中ssh远程报错:packet_write_wait: Connection to 192.168.163.190 port 22: Broken pipe lost connection
  3. E: Could not get lock /var/lib/dpkg/lock-frontend - open (11: Resource temporarily unavailable)
  4. PostgreSQL 9.6.6启动
  5. 查看局域网内所有ip 和 mac
  6. 【Python-3.5】绘制随机漫步图
  7. Xshell连接mysql数据库乱码问题解决思路总结
  8. vue init失败解决方案-终极版
  9. 关于ElementUI中MessageBox弹框的取消键盘触发事件(enter,esc)关闭弹窗(执行事件)的解决方法
  10. IIS配置Url重写实现http自动跳转https的重定向方法(100%解决)