Promise API 简介
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, 所以只需要通过 then
和 catch
方法处理结果即可!
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 简介相关推荐
- 线程编程常见API简介(中)
2019独角兽企业重金招聘Python工程师标准>>> 一.概述 在<线程编程常见API简介(上) >中讲述了有关线程创建过程中常用的 API 的使用方法,本节继续讲述有 ...
- WebSocket API简介
WebSocket是html5新增加的一种通信协议,目前流行的浏览器都支持这个协议,例如Chrome,Safari,Firefox,Opera,IE等等,对该协议支持最早的应该是chrome,从chr ...
- web API简介(二):客户端储存之document.cookie API
概述 前篇:web API简介(一):API,Ajax和Fetch 客户端储存从某一方面来说和动态网站差不多.动态网站是用服务端来储存数据,而客户端储存是用客户端来储存数据.document.cook ...
- 【Netty】NIO 网络通信 SelectionKey 常用 API 简介
文章目录 I . SelectionKey 简介 II . SelectionKey 事件简介 III . SelectionKey 常用 API 简介 I . SelectionKey 简介 1 . ...
- 【Java 网络编程】TCP API 简介 ( Socket | ServerSocket )
文章目录 I Socket API 简介 II ServerSocket API 简介 III Socket 数据交互 IV Socket 客户端操作流程 V Socket 服务器端操作流程 VI S ...
- java编译器使用教程_Java编译器API简介
今天给大家分享的是Java编译器API简介,文章部分内容摘自[优锐课]学习笔记. Java编译器API Java编译器API是Java模块(称为java.compiler)的一部分.该模块包括语言模型 ...
- html5画电池状态,HTML5的一个显示电池状态的API简介
这篇文章主要介绍了HTML5的一个显示电池状态的API简介,由Mozilla设计,具体的设备和浏览器支持情况还要通过检测才能确定,需要的朋友可以参考下 移动设备的份额在网络流量中在大量增长,其所贡献的 ...
- ZABBIX API简介及使用
API简介 Zabbix API开始扮演着越来越重要的角色,尤其是在集成第三方软件和自动化日常任务时.很难想象管理数千台服务器而没有自动化是多么的困难.Zabbix API为批量操作.第三方软件集成以 ...
- 基于阿里云的API简介
基于阿里云的API简介 API简介 如果您熟悉网络服务协议和一种以上编程语言,推荐您调用API管理您的云上资源和开发自己的应用程序. 使用说明 ECS API支持HTTP或者HTTPS网络请求协议,允 ...
最新文章
- ORA-01855: AM/A.M. or PM/P.M. required错误解决
- Nginx使用webbench进行压力测试
- 《系统集成项目管理工程师》必背100个知识点-58沟通方式
- linux中查找某一个字符串,Linux系统下,在文件中查找某个字符串
- python分组函数_Python中如何按列分组和按自己的函数汇总
- python无条件跳转_python按按钮实现界面跳转_python实现界面跳转 - CSDN
- 爬取人民日报_【爬虫系列】人民日报半个世纪的资料(文末福利)
- ASP.NET MVC+LINQ开发一个图书销售站点(6):创建数据层
- 滴滴回应高额抽成:确实存在;抖音火山版被判赔腾讯 800 万元;华为鸿蒙系统有望下月规模化推送|极客头条...
- Leetcode 129. 根到叶子结点数字之和
- java this()函数_Java经典面试题之(如何正确的使用this?)
- 物联网单片机毕业设计实现
- php date 函数用法,PHP日期时间函数date()使用方法
- 23种PHP开发工具集合
- jquery获取ip地址
- Linux的系统安全及管理
- QML:ListView按下选中当前项和高亮的一例
- 【PowerQuery】Excel 自动刷新PowerQuery连接
- Calendar 日历
- 数据读取机制Dataloader和Dataset和Transforms
热门文章
- 处理Linux中大量ESTABLISHED进程
- Ubuntu中ssh远程报错:packet_write_wait: Connection to 192.168.163.190 port 22: Broken pipe lost connection
- E: Could not get lock /var/lib/dpkg/lock-frontend - open (11: Resource temporarily unavailable)
- PostgreSQL 9.6.6启动
- 查看局域网内所有ip 和 mac
- 【Python-3.5】绘制随机漫步图
- Xshell连接mysql数据库乱码问题解决思路总结
- vue init失败解决方案-终极版
- 关于ElementUI中MessageBox弹框的取消键盘触发事件(enter,esc)关闭弹窗(执行事件)的解决方法
- IIS配置Url重写实现http自动跳转https的重定向方法(100%解决)