Promise
Promise是个十分优雅的词,他的中文含义是承诺、约定的意思,在古今中外都有非常多的和“承诺”相关的历史故事、寓言故事和名言名句,那么今天我们就来一起了解下JavaScript中的Promise吧!
文章目录
Promise一、Promise基础特点一: `promise`的状态一旦改变就无法更改特点二:`promise`实例内部本身是同步执行的 二、`promise`的静态方法`Promise.resolve()``Promise.reject()` 三、`Promise`的实例方法1、`Promise.then()`2、`Promise.catch()`3、`Promise.finally()` 总结一、Promise基础
promise
是ES6新增的引用类型,可以通过 new 操作符来实例化。创建新的promise需要传入执行器(executor)函数作为参数。
我们new一个Promise实例:
const promise = new Promise(function(resolve, reject) {resolve(value);});
Promise
对象有以下两个特点。
(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending
变为fulfilled
和从pending
变为rejected
。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为resolved
(已定型)。如果改变已经发生了,你再对Promise
对象添加回调函数,也会立即得到这个结果。这与事件(Event
)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
特点一:promise
的状态一旦改变就无法更改
我们看一个例子就可以清晰了解到promise
的状态特点:
const p = new Promise((resolve,reject) => {resolve()reject()})const p2 = new Promise((resolve,reject) => {reject()resolve()})console.log(p)//Promise {<fulfilled>: undefined}console.log(p2)//Promise {<rejected>: undefined}
所以我们总结promise
的第一个特点: promise的状态一旦改变就无法更改
特点二:promise
实例内部本身是同步执行的
在初始化promise
时,执行器已经改变了每个promise
的状态。我们知道执行器函数是同步执行的。我看看一个例子:
console.log('a')setTimeout(function(){console.log('f')}, 200)const p = new Promise(resolve => {console.log('b')resolve('g')console.log('c')})setTimeout(function(){console.log('e')}, 0)console.log('d')//答案:/*abcdef*/
如果看不懂执行js执行机制可以先阅读我上一篇文章【JavaScript】JS执行机制微任务和宏任务
所以我们总结promise
的第二个特点:promise本身是同步执行的
二、promise
的静态方法
这里先介绍两个最基本的静态方法,下一篇文章会带来:race
、allSettled
、All
、any
的拓展静态方法
Promise.resolve()
通过调用Promise.resolve()方法我们可以实例化一个解决的Promise
下面两个实例的结果实际上是一样的:
const p1 = new Promise(resolve => {resolve()})const p2 = Promise.resolve()console.log(p1)//Promise {<fulfilled>: undefined}console.log(p2)//Promise {<fulfilled>: undefined}console.log(p1==p2)
Promise.reject()
与Promise.resolve()
一样,Promise.reject()
实例化一个拒绝状态的Promise
并抛出错误。
下面两个实例的结果实际上是一样的:
const p1 = new Promise(reject => {reject()})const p2 = Promise.reject()console.log(p1)//Promise {<rejected>: undefined}console.log(p2)//Promise {<rejected>: undefined}
三、Promise
的实例方法
1、Promise.then()
Promise.then()
接收最多两个参数:onResolved
和onRejected
。两个参数都是可选的,如果提供的话promise
会进入“fulfilled”和“rejected”状态时执行。
我看来看一下例子:
const p1 = new Promise((resolve,reject )=> {setTimeout(function(){resolve('我是resolve,成功状态');}, 2000);});const p2 = new Promise((resolve,reject )=> {setTimeout(function(){reject ('我是reject,失败状态');}, 2000);});p1.then((res)=>{console.log(res)},(err)=>{console.log(err)}) //我是resolve,成功状态p2.then(null,(err)=>{console.log(err)})// 我是reject,失败状态
因为期约状态只有一次所以onResolved
和onRejected
这两个操作一定是互斥的。
传给.then()的任何非函数类型的参数都会被静默忽略。所以我们一般只提供一个参数,那么在另一个状态的参数上我们传入null。可以有助于避免在内存中创建多余的对象。
我们根据特性:传给.then()的任何非函数类型的参数都会被静默忽略做一道习题:
Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log)//第一个then和第二个then中传入的都不是函数,一个是数字,一个是对象,因此发生了透传,将resolve(1) 的值直接传到最后一个then里。所以输出结果为:1
2、Promise.catch()
catch方法用于给Promise
添加拒绝处理程序。这个方法只接收一个参数,事实上他就是.then的一个语法糖,调用它就相当于上文中的:
Promise.then(null,(err)=>{ console.log(err)})
根据(事实上他就是.then的一个语法糖)这一个特点,我们再来结合Promise特点一(promise的状态一旦改变就无法更改) 和 .then的特点(Promise.then()
接收最多两个参数:onResolved和onRejected)做一道综合练习题:
Promise.reject('err!!!').then((res) => {console.log('success', res)}, (err) => {console.log('error', err)}).catch(err => {console.log('catch', err)})// 在这道题中,错误直接被then的第二个参数捕获了,所以就不会被catch捕获了,输出结果为:'error' 'error!!!'
3、Promise.finally()
finally()
方法用于指定不管Promise
对象最后状态如何,都会执行的操作。该方法是 ES 引入标准的。
promise.then((result) => {/* ···*/}) .catch((error) => {/* ···*/}) .finally(() => {/* ···*/});
下面是一个例子,服务器使用 Promise 处理请求,然后使用finally方法关掉服务器。
server.listen(port) .then(function() {/* ... */ }) .finally(server.stop);
finally方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是fulfilled还是rejected。这表明,finally方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。
我们来看一道习题了解finally的特性:
Promise.resolve('1').then(res => {console.log(res)}).finally(() => {console.log('finally')})Promise.resolve('2').finally(() => {console.log('finally2')return '我是finally2返回的值'}).then(res => {console.log('finally2后面的then函数', res)})/*结果: 1finally2finallyfinally2后面的then函数 2*/
finally本质上是then方法的特例。
总结
那么最后总结一下promise
的几个小特点:
特点一:promise
的状态一旦改变就无法更改特点二:promise
实例内部本身是同步执行的特点三:Promise.then()
接收最多两个参数:onResolved
和onRejected
。两个参数都是可选的,如果提供参数的话promise
会进入“fulfilled”和“rejected”状态时执行。特点四:传给.then()
的任何非函数类型的参数都会被静默忽略特点五:Promise.catch()
只接收一个参数。事实上他就是.then的一个语法糖 相当于:Promise.then(null,(err)=>{ console.log(err)})
只是我们不用传递第一个null参数了特点六:Promise.finally()
方法不管Promise对象最后的状态如何都会执行特点七:finally()
方法的回调函数不接受任何的参数,也就是说你在.finally()函数中是无法知道Promise最终的状态是resolved还是rejected的特点八:finally()
它最终返回的默认会是一个上一次的Promise
对象值,不过如果抛出的是一个异常则返回异常的Promise
对象。