深入理解promise
如今promise大行其道,关于异步方面的几乎都有它的影子,新的fetch api返回的是promise对象,generator中的yield后面一般也会跟promise对象,async的await后面一般也是promise对象。
既然promise这么重要,这里也整理了一些关于它的知识,加深下自己对promise的理解。
1,基础
promise是一个异步操作的最终结果。它有三种状态,初始状态为Pending,状态只能转变为resolved或者rejected,并且不可逆。
基本用法为
let promise = new Promise((resolve, reject) => {
//异步代码....
if (/*操作成功 */) {
resolve(result)
} else {
reject(error)
}
})
必须有then方法,接受两个可选的函数参数:onResolve和onRejected。then方法必须返回一个promise对象以便接下来的链式调用。为了保证其中回调的执行顺序,回调必须使用异步。
2,API
实例方法:
.then(onResolve, onReject) : promise状态改变时的回调,返回一个新的promise实例
.catch() : 本质上就是then方法中的onReject,返回值是一个新的promise
静态方法:
Promise.resolve() : 1,将对象转为promise对象。
2,如果参数是promise实例,直接返回
3,如果参数为thenable对象,则转换为promise对象,并执行then方法
4,如果参数为原始类型,返回一个promise对象,状态为resolved,参数为那个原始类型
5,如果没有参数则返回一个状态为resolved的promise的对象
Promise.reject() : 和上面的差不多,只是状态改变为rejected
Promise.all() : 1,接收一个promise实例的数组
2,如果全部成功,则状态转为resolved,返回值为一个数组
3,只要有一个失败,状态就转为rejected,直接返回错误
4,返回值也是为新的promise对象
Promise.race() : 和all差不多,不同的是只要有一个实例的状态改变了就结束了。
3,promise的误区
1,把promise当做callback来使用
getData1().then(res1 => {
getData2(res).then(res2 => {
getData3(res).then(......)
})
})
promise的目的本来就是用来解决异步回调地狱的,这种写法虽然可行,但完全违背了promise的设计初衷。
可以改成以下的写法:
getData1()
.then(res1 => {
return getData2(res1)
})
.then(res2 => {
return getData3(res2)
})
.then(......)
2,没有处理错误
如果在使用promise时没有处理错误,promise抛出的错误将不会传递到外层代码,即不会有任何反应,不会终止当前脚本的继续执行。
promise捕获错误有两种方式: 一种是在then中定义rejected状态的回调(then的第二个参数),第二种是用catch方法
由于promise对象的错误具有冒泡的性质,会一直向后传递,也就是说错误总是会被下一个catch捕获。所以一般来说,不要在then方法中定义rejected状态的回调,而总是使用catch来捕获错误。使用catch可以捕获到前面的then方法中执行的错误。
4,promise.resolve()
promise.resolve还有一个作用,就是将现有的对象转为promise对象
thenable对象指的是具有then方法的对象。比如:
let thenable = {
then: function(resolve,reject) {
resolve(111)
}
}
promise.resolve方法会将这个对象转为Promise对象,然后立即执行里面的then方法。
let thenable = {
then: function (resolve, reject) {
resolve(123)
}
}
let p = Promise.resolve(thenable)
p.then(result => {
console.log(result) //
})
then方法执行后,对象p的状态就变为resolved,从而立即执行紧跟着的then方法的回调函数。
5,promise.reject()
let p = Promise.reject('出错了')
等同于
let p = new Promise((resolve, reject) => reject('出错了'))
Promise.reject()的参数会原封不动的作为后续方法的参数,这一点与Promise.resolve方法不一致。
const thenable = {
then (resolve, reject) {
reject('错误!')
}
}
Promise.reject(thenable).catch(e => {
console.log(e === thenable) // true
})
上面的代码中,Promise.reject()的参数为一个thenable对象,执行之后,后面catch方法的参数不是reject抛出的错误这个字符串,而是thenable对象。
6,附加方法
1,done()
由于Promise的错误不会冒泡到全局,所以Promise链式调用时,最后一个方法如果抛出错误,不管是then还是catch,都有可能无法捕捉到,这里的done方法,总是处于回调链的末端,保证抛出的任何错误都能被捕捉到。
Promise.prototype.done = (onResolved, onRejected) => {
this.then(onResolved, onRejected).catch( reason => {
setTimeout(() => {throw reason}, 0)
})
}
done方法可以像then方法那样使用,提供resolved和rejected状态的回调函数。
2,finally()
不管Promise对象最后的状态如何,finally参数的回调函数都会执行。
Promise.prototype.finally = callback => {
let P = this.constructor
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.reject(callback()).then(() => {throw reason})
)
}
7,实战应用
图片懒加载
let images = []
function loadImg(url) {
return new Promise((resolve, reject) => {
let img = new Image()
img.onload = () => resolve(img)
img.onerror = reject
img.src = url
})
}
function preLoadImg(imgs) {
let arr = []
imgs.forEach(url => {
let image = loadImg(url).then(img => images.push(img)).catch(error => console.log(error))
arr.push(image)
})
Promise.all(arr).then(() => {
console.log('全部图片加载完成之后要处理的事情')
})
}
深入理解promise的更多相关文章
- 大白话讲解Promise(二)理解Promise规范
上一篇我们讲解了ES6中Promise的用法,但是知道了用法还远远不够,作为一名专业的前端工程师,还必须通晓原理.所以,为了补全我们关于Promise的知识树,有必要理解Promise/A+规范,理解 ...
- 彻底理解Promise对象——用es5语法实现一个自己的Promise(上篇)
本文同步自我的个人博客: http://mly-zju.github.io/ 众所周知javascript语言的一大特色就是异步,这既是它的优点,同时在某些情况下也带来了一些的问题.最大的问题之一,就 ...
- 理解Promise的三种姿势
译者按: 对于Promise,也许你会用了,却并不理解:也许你理解了,却只可意会不可言传.这篇博客将从3个简单的视角理解Promise,应该对你有所帮助. 原文: Three ways of unde ...
- 理解Promise的3种姿势
译者按: 对于Promise,也许你会用了,却并不理解:也许你理解了,却只可意会不可言传.这篇博客将从3个简单的视角理解Promise,应该对你有所帮助. 原文: Three ways of unde ...
- 分步理解 Promise 的实现
一个 Promise 的运用: var firstPromise = new Promise(function(resolve,reject){ setTimeout(function(){ var ...
- 理解promise 02
1:promise是什么? 就是(链式)包装的回调函数. 2:语法 new Promise( function(resolve, reject) {...} /* executor */ ); exe ...
- 160701、理解 Promise 的工作原理
Javascript 采用回调函数(callback)来处理异步编程.从同步编程到异步回调编程有一个适应的过程,但是如果出现多层回调嵌套,也就是我们常说的厄运的回调金字塔(Pyramid of Doo ...
- 160623、理解 Promise 的工作原理
Javascript 采用回调函数(callback)来处理异步编程.从同步编程到异步回调编程有一个适应的过程,但是如果出现多层回调嵌套,也就是我们常说的厄运的回调金字塔(Pyramid of Doo ...
- 理解Promise简单实现的背后原理
在写javascript时我们往往离不开异步操作,过去我们往往通过回调函数多层嵌套来解决后一个异步操作依赖前一个异步操作,然后为了解决回调地域的痛点,出现了一些解决方案比如事件订阅/发布的.事件监听的 ...
- 理解promise 01
原文地址: http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html 用Javascript的小伙伴们,是时候承认了,关于 ...
随机推荐
- linux内核被加载的过程
二,linux内核被加载的过程 一,linux安装时遇到的概念解析 内核必须模块vmlinz(5M左右)不认识硬盘,原本是需要写跟loader中一样的内容,来加载非必要模块. 内核非必要的功能被编译为 ...
- Django框架 之 查询 Extra
Django框架 之 查询 Extra extra 1 2 extra(select=None, where=None, params=None, tables=None, order_b ...
- 关于 Azure 安全性的 10 点提示
讨论云服务时,安全性是一个关键领域.实际上,Windows Azure 基础结构实施大量的技术和流程来保护环境.此页介绍 Microsoft 的全球基础服务如何运行基础结构以及它们实施的安全措施. 从 ...
- 解决"要执行请求的操作,WordPress需要访问您网页服务器的权限"
比如我们在VPS主机中创建WordPress站点的时候,会有需要在线安装主题.插件等,但是点击下载安装的时候会有"要执行请求的操作,WordPress需要访问您网页服务器的权限. 请输入您的 ...
- Vue vue-resource发送Http请求
vue-resource 1.cnpm install vue-resource --save 2.在main.js中import VueResource from 'vue-resource' 3. ...
- 分别实现数组所有元素相加、相乘、相与——FP 风格
var ops = { "plus": (x,y)=>x+y, "mul" : (x,y)=>x*y, "and" : (x,y ...
- 十三、Node.js-fs模块(上)
Node.js内置的fs模块就是文件系统模块,负责读写文件以及对文件进行相关操作. 下面直接可参考下面的代码进行fs模块里面基本方法的学习: /** * Created by Administrato ...
- Linux环境下jdk、tomcat、redis安装及配置
环境说明: linux : centOS jdk : 1.8 tomcat : 8.5 redis : 4.0 jdk安装配置 1.下载jdk(这里下载的是jdk-8u181-linux-x64.ta ...
- python3关于date和time的标准库
python3中关于日期和时间的标准库datetime和time,之前都是用的时候随用随查,今天系统的看一下用这两个库可以做些什么. 1.time标准库 #首先添加一个time对象,看一下该对象的属性 ...
- python 时间相关函数
python 中与时间处理相关的模块包括 time.datetime.以及 calendar time 模块 time() 函数:time() 函数用于返回当前时间的时间戳(1970年01月08时00 ...