Promise简介
Promise 是异步编程的一种解决方案: 从语法上讲,promise
是一个对象,从它可以获取异步操作的消息;从本意上讲,它是承诺,承诺它过一段时间会给你一个结果。
promise
有三种状态:**pending
(等待态),fulfiled
(成功态),rejected
(失败态)** ;状态一旦改变,就不会再变。创造promise
实例后,它会立即执行。
promise
解决的问题:
- 回调地狱,代码难以维护, 常常第一个的函数的输出是第二个函数的输入这种现象
promise
可以解决异步的问题,但不能说promise
是异步的(注意promise
本身是同步的)
Promise的基本使用
由下面可知:then
,catch
,finally
都是Promise的实例方法,放在Promise.prototype
上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| console.log(Object.getOwnPropertyDescriptors(Promise.prototype));
|
创建
使用 new Promise
构造函数可以创建一个 Promise
对象,并提供一个执行器函数(executor function)
,该函数有两个参数,通常命名为 resolve
和 reject
:
1 2 3 4 5 6 7 8
| const myPromise = new Promise((resolve, reject) => { if () { resolve('Promise is resolved successfully.'); } else { reject('Promise is rejected with an error.'); } });
|
使用
then() 和 catch() 方法
.then(onFulfilled, onRejected)
:当 Promise 被成功解决时,调用 onFulfilled 回调;如果被拒绝,则调用 onRejected 回调。
.catch(onRejected)
:用于指定当 Promise 被拒绝时的回调函数。
1 2 3 4 5 6 7
| myPromise .then((value) => { console.log(value); }) .catch((error) => { console.error(error); });
|
或者:
1 2 3 4 5 6
| myPromise .then((value) => { console.log(value); }, catch((error) => { console.error(error); }))
|
finally() 方法
.finally(onFinally)
:无论 Promise 对象是被解决还是被拒绝,都会执行的回调函数。
1 2 3 4
| myPromise .then((value) => console.log(value)) .catch((error) => console.error(error)) .finally(() => console.log('Promise is settled.'));
|
链式调用
Promise
的 then()
和 catch()
方法返回的都是一个新的 Promise
对象,这允许进行链式调用。
1 2 3 4 5 6 7 8 9 10 11
| myPromise .then((firstResult) => { return anotherAsyncOperation(); }) .then((secondResult) => { }) .catch((error) => { });
|
Promise状态
三种状态
一个 Promise 对象有三种状态:
- Pending(进行中) :初始状态,既不是成功,也不是失败状态。
- Fulfilled(已成功) :操作成功完成。
- Rejected(已失败) :操作失败。
Promise 的状态转移是单向的,只能从 Pending
到 Fulfilled
或 Pending
到 Rejected
,不能逆向转换,也不能从成功或失败状态转回进行中状态。
resolve()
的参数决定promise
状态
当 Promise 的 resolve
方法被调用时,其参数决定了 Promise 的状态:
- 如果参数是一个普通值或普通对象(非 Promise 对象) ,则 Promise 对象变为
fulfilled
(已解决)状态,并且该值成为 Promise 的结果值。
1 2 3 4 5 6 7
| const promise = new Promise((resolve, reject) => { setTimeout(() => { resolve('success') }, 1000) })
promise.then((data) => {console.log(data);})
|
如果参数是一个 Promise 对象,则原始 Promise 对象的状态取决于被解析的 Promise 对象的状态:
- 如果被解析的 Promise 对象是
pending
状态,则原始 Promise 对象也保持 pending
状态,直到被解析的 Promise 对象状态改变。
- 如果被解析的 Promise 对象是
fulfilled
(已解决)状态,则原始 Promise 对象也变为 fulfilled
状态,并且其值为被解析的 Promise 对象的值。
- 如果被解析的 Promise 对象是
rejected
(已拒绝)状态,则原始 Promise 对象也变为 rejected
状态,并且其原因为被解析的 Promise 对象的原因。
1 2 3 4 5 6 7 8 9 10 11
| const promise = new Promise((resolve, reject) => { setTimeout(() => { resolve(new Promise((resolve, reject) =>{ reject("现在状态是rejected")
})) }, 1000) })
promise.then((data) => {console.log(data);}) .catch((error) => {console.log(error);})
|
如果参数是一个 thenable 对象(具有 then
方法的对象) ,其行为类似于一个 Promise 对象:
- 如果 thenable 对象的
then
方法被成功调用,则原始 Promise 对象也变为 fulfilled
状态,并且其值为 thenable 对象 resolve
后的值。
- 如果 thenable 对象的
then
方法抛出异常,则原始 Promise 对象也变为 rejected
状态,并且其原因为 thenable 对象抛出的异常。
1 2 3 4 5 6 7 8 9 10 11 12 13
| const thenableObj = { then(resolve, reject){ resolve('我是thenable对象') } } const promise = new Promise((resolve, reject) => { setTimeout(() => { resolve(thenableObj) }, 1000) })
promise.then((data) => {console.log(data);}) .catch((error) => {console.log(error);})
|
then
方法
多次调用then
方法
一个promise
可以多次调用then
方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const promise = new Promise((resolve, reject) => { setTimeout(() => { resolve('success') }, 1000) })
promise.then((data) => {console.log(data);}) promise.then((data) => {console.log(data);}) promise.then((data) => {console.log(data);})
|
then
方法的返回值(链式调用)
和resolve()
的参数决定promise状态类似。then
方法的返回值都会作为执行完then
方法后新产生的promise的resolve的参数。 默认不写的话就等同于return undefined
会把undefined
作为resolve的参数。
- 返回一个普通值(数值/字符串/普通对象/
undefined
),那么这个返回的普通值将会作为新promise
中resolve
的参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const promise = new Promise((resolve, reject) => { setTimeout(() => { resolve('success') }, 1000) })
promise.then((data1) => { console.log(data1) return data1 }) .then(data2 => {console.log(data2)})
|
- 返回一个
promise
,则新 Promise 的状态取决于被返回的 Promise 的状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const promise = new Promise((resolve, reject) => { setTimeout(() => { resolve('success') }, 1000) })
promise.then((data1) => { console.log(data1) return new Promise((resolve,reject) => { setTimeout(() => { reject('failure') }, 1000) }) }) .then(data2 => {console.log(data2)}) .catch((error) => {console.log(error)})
|
- 返回一个 thenable 对象(具有
then
方法的对象),其行为类似于一个 Promise 对象:
- 如果 thenable 对象的
then
方法被成功调用,则原始 Promise 对象也变为 fulfilled
状态,并且其值为 thenable 对象 resolve
后的值。
- 如果 thenable 对象的
then
方法抛出异常,则原始 Promise 对象也变为 rejected
状态,并且其原因为 thenable 对象抛出的异常。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| const thenableObj = { then(resolve, reject){ resolve('我是thenable对象') } }
const promise = new Promise((resolve, reject) => { setTimeout(() => { resolve('success') }, 1000) })
promise.then((data1) => { console.log(data1) return thenableObj }) .then(data2 => {console.log(data2)}) .catch((error) => {console.log(error)})
|
catch
方法
catch
方法不仅可以捕获reject
,也可以捕获throw new Error()
1 2 3 4 5 6 7 8 9 10
| const promise = new Promise((resolve, reject) => { setTimeout(() => { resolve('success') }, 1000) })
promise.then(success => console.log(success), error => console.log(error))
promise.then(success => console.log(success)).catch(error => console.log(error))
|
- 不能分开分别调用
then()
和catch()
,要么写成Promise A+的形式,要么写成ES6的形式。但是和then
一样,catch
也可以进行多次调用。
catch()
按照顺序的优先级来捕获reject
或throw new Error()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const promise = new Promise((resolve, reject) => { setTimeout(() => { resolve('success') }, 1000) })
promise.then(success => { console.log(success) return new Promise((resolve, reject) => { setTimeout(() => { reject('new Promise error') }, 1000) }) }) .catch(error => console.log(error))
|
上面代码中,最开始的promise
是resolve
,不会捕获异常,而then
返回的是一个promise
,其reject
,故catch
会捕获到reject('new Promise error')
。
但下面这个例子中,最开始的promise
是reject
,会被catch
捕获到,那么后面then
返回的promise
,虽然是reject
,但是不会被捕获到。
catch
就是按照这样的顺序优先级来捕获的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const promise = new Promise((resolve, reject) => { setTimeout(() => { reject('failure') }, 1000) })
promise.then(success => { console.log(success) return new Promise((resolve, reject) => { setTimeout(() => { reject('new Promise error') }, 1000) }) }) .catch(error => console.log(error))
|
catch
和then
一样,也可以有返回值,而且和then
一样,返回的值会被传到new Promise
的resolve
。
finally
方法
- 不管
resolve
还是reject
最终都会执行的。
- 回调函数没有参数。
finally
也可以多次调用。
Promise的类方法(静态方法)
Promise.resolve()
与Promise.reject()
方法
用于返回成Promise。
Promise.resolve()
还是由resolve()的参数决定promise状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| const promise1 = Promise.resolve({a:1, b:2}) promise1.then(data1 => console.log(data1))
const promise1 = new Promise((resolve, reject) => { resolve({a:1, b:2}) }) promise1.then(data1 => console.log(data1))
const promise2 = Promise.resolve(new Promise((resolve, reject) => resolve("hello, I'm a promise"))) promise2.then(data2 => console.log(data2))
const promise2 = new Promise((resolve, reject) => { resolve(new Promise((resolve, reject) => resolve("hello, I'm a promise"))) }) promise2.then(data2 => console.log(data2))
const thenableObj = { then(resolve, reject){ resolve('我是thenable对象') } } const promise3 = Promise.resolve(thenableObj) promise3.then(data3 => console.log(data3))
const promise3 = new Promise((resolve, reject) => { resolve(thenableObj) }) promise3.then(data3 => console.log(data3))
|
考考你,下面这段代码会输出什么?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| Promise.resolve() .then(() => { console.log(0); return Promise.resolve(4); }) .then((res) => { console.log(res) })
Promise.resolve() .then(() => { console.log(1); }) .then(() => { console.log(2); }) .then(() => { console.log(3); }) .then(() => { console.log(5); }) .then(() => { console.log(6); })
|
分析:
- 一个promise
resolve
后,状态变成Fulfilled
,会把then()
里面的回调函数放到微队列里面执行;相对应的, reject
后,状态变成Rejected
,会把catch()
里面的回调函数放到微队列里面执行。
then()
方法会返回一个promise。
- 如果promise1
resolve(普通值a)
后在then()
中return了一个新的promise(promise2),(V8源码中)那么就会把promise2.then((普通值a)=> promise1的then()返回的promise .resolve(普通值a))
这一段代码放到微队列里面等待执行。
Promise.reject()
注意:reject
可不会和resolve
一样由参数来决定promise状态,不管传的参数是什么都只会执行catch
。
1 2 3 4 5 6 7 8 9
| const thenableObj = { then(resolve, reject){ resolve('我是thenable对象') } } const promise = Promise.reject(thenableObj) promise.then(data => console.log(data)) .catch((error) => {console.log(error)})
|
Promise.all()
和Promise.allSettled()
Promise.all()
- 当所有的promise都
resolve
后会以数组的形式返回所有resolve
的结果,顺序是按照写在Promise.all()
里面的顺序,而不是按照每个promise
响应的顺序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('我是promise1') }, 1000) })
const promise2 = new Promise((resolve, reject) => { setTimeout(() => { resolve('我是promise2') }, 2000) })
const promise3 = new Promise((resolve, reject) => { setTimeout(() => { resolve('我是promise3') }, 3000) })
Promise.all([promise3, promise2, promise1]).then(res => { console.log(res); })
|
- 只要这些promise中有一个
reject
了,那么就会直接catch
出reject
的那个promise( 只会catch
出最先reject的那个,一遇到reject
就会立即catch
)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('我是promise1') }, 1000) })
const promise2 = new Promise((resolve, reject) => { setTimeout(() => { reject('我是promise2,reject了') }, 2000) })
const promise3 = new Promise((resolve, reject) => { setTimeout(() => { resolve('我是promise3') }, 3000) })
Promise.all([promise3, promise2, promise1]).then(res => { console.log(res); }) .catch(err => console.log(err));
|
Promise.allSettled()
Promise.allSettled()
则会等所有promise都响应完最后直接输出一个 对象数组,里面包含每个promise的status和value/reason , 顺序还是按照写在Promise.allSettled()
里面的顺序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('我是promise1') }, 1000) })
const promise2 = new Promise((resolve, reject) => { setTimeout(() => { reject('我是promise2,reject了') }, 2000) })
const promise3 = new Promise((resolve, reject) => { setTimeout(() => { resolve('我是promise3') }, 3000) })
Promise.allSettled([promise3, promise2, promise1]).then(res => { console.log(res); }) .catch(err => console.log(err));
|
Promise.race()
和Promise.any()
Promise.race()
会调用第一个响应完的promise的then()
或catch()
。
- 只要有一个Promise变成
fulfilled
状态,那么就结束,执行相应的then()
- 只要有一个Promise变成
rejected
状态,那么就结束,执行相应的catch()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('我是promise1') }, 1000) })
const promise2 = new Promise((resolve, reject) => { setTimeout(() => { reject('我是promise2,reject了') }, 500) })
const promise3 = new Promise((resolve, reject) => { setTimeout(() => { resolve('我是promise3') }, 3000) })
Promise.race([promise3, promise2, promise1]).then(res => { console.log(res); }) .catch(err => console.log(err));
|
Promise.any()
总是调用第一个resolve
的promise的then()
。
Promise.any()
方法会等到一个fulfilled
状态,才会决定新Promise的状态
- 如果所有的Promise都是
reject
的,那么也会等到所有的Promise都变成rejected
状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| const promise1 = new Promise((resolve, reject) => { setTimeout(() => { reject('我是promise1,reject了') }, 1000) })
const promise2 = new Promise((resolve, reject) => { setTimeout(() => { reject('我是promise2,reject了') }, 500) })
const promise3 = new Promise((resolve, reject) => { setTimeout(() => { reject('我是promise3,reject了') }, 3000) })
Promise.any([promise3, promise2, promise1]).then(res => { console.log(res); }) .catch(err => console.error(err));
|
Promise A+ 规范与ES6的promise
- ES6(ECMAScript 2015)中的
Promise
是语言规范的一部分,并且现代浏览器和 JavaScript 运行环境都原生支持它。
- ES6 的
Promise
是 JavaScript 异步编程的一个基础构件,它提供了一种更合理、更强大的异步编程模型。而 Promise A+
规范是 Promise
的行为标准,确保了不同 JavaScript 环境中 Promise
的一致性和可预测性。
- 在实际开发中,你通常不需要自己实现
Promise
,而是直接使用 ES6 提供的 Promise
对象,或者使用库和框架提供的符合 Promise A+
规范的 Promise
实现。
ES6 Promise 的基本用法
ES6 中的 Promise
是一个构造函数,是对Promise A+ 规范的实现。注意:构造函数本身不是Promise,而是其创建的对象是Promise。ES6 中的 Promise
还增加了catch()
,finally()
,Promise.all()
,Promise.allSettled()
,Promise.race()
,Promise.any()
创建 Promise
1 2 3 4 5 6 7 8 9
| const myPromise = new Promise((resolve, reject) => { const condition = true; if (condition) { resolve('Promise is resolved successfully.'); } else { reject('Promise is rejected with an error.'); } });
|
使用 Promise
1 2 3 4 5 6 7
| myPromise .then((value) => { console.log(value); }) .catch((error) => { console.error(error); });
|
Promise A+ 规范
Promise A+
是 Promise
的一个规范,早于ES6,它定义了 Promise
的行为和接口,它的出现是为了解决回调地狱的问题。ES6 中的 Promise
实现遵循了这个规范。Promise A+
规范确保了不同 JavaScript 环境中 Promise
的一致性。
Promise A+ 规范的关键点
- 状态:
Promise
对象有三种状态:pending
(进行中)、fulfilled
(已成功)和 rejected
(已失败)。
- thenable 对象:遵循
Promise A+
规范的 Promise
对象被称为 thenable
对象,因为它们拥有 then
方法。
- 链式调用:
Promise
的 then
方法返回一个新的 Promise
对象,这允许进行链式调用。
- 错误处理:如果在
.then()
或 .catch()
方法中抛出错误,那么这个错误会被下一个 .catch()
方法捕获。
- 回调函数:
Promise
的构造函数接受的执行器函数(executor function)中,resolve
用于解决 Promise
,reject
用于拒绝 Promise
。
- 惰性执行:
Promise
中的异步操作是惰性执行的,即直到 Promise
的 .then()
或 .catch()
方法被调用时才开始执行。
Promise 与 Promise A+ 的关系
- Promise A+ 是规范:它定义了
Promise
应该如何工作,包括它的接口和行为。
- ES6 Promise 是实现:ES6 中的
Promise
是对 Promise A+
规范的一个具体实现。
- 兼容性:遵循
Promise A+
规范的任何 Promise
实现都应该与遵循相同规范的其他 Promise
实现兼容。
手写promise
手写Promise的工具函数
1 2 3
| Promise.prototype.catch = function (onRejected) { return this.then(null, onRejected) }
|
catch
方法(Promise A+规范里面没有catch()
)实际上是通过调用 then
方法来实现的。具体地,它传递了 null
作为第一个参数(表示对于解决的情况不做处理),并将传入的 onRejected
回调函数作为第二个参数(用于处理拒绝的情况)。因此,当 Promise
被拒绝时,onRejected
回调函数将被调用,而对于解决的情况,则不做处理。
finally
:1 2 3 4 5 6 7 8 9 10 11
| finally(onFinally){ return this.then(data =>{ onFinally() return data }), err => { onFinally() throw err } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function isPromiseLike(obj){ return obj && obj.then === 'function' }
Promise.resolve = function(value){ if(value instanceof Promise) return value if(isPromiseLike(value)){ return new Promise((resolve, reject) => {value.then(resolve, reject)}) } return new Promise((resolve, reject) => {resolve(value)}) }
|
reject
:1 2 3 4
| Promise.reject = function(reason){ return new Promise((resolve, reject) => {reject(reason)}) }
|
手写Promise(完整版)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
| const PENDING = 'pending' const FULFILLED = 'fulfilled' const REJECTED = 'rejected' class MyPromise { #state = PENDING #result = undefined #handlers = []
#changeState(state, result){ if(this.#state !== PENDING) return this.#state = state this.#result = result this.#run() } #isPromiseLike(value){ return value && typeof value.then === 'function' } #runMicroTask(func){ if(typeof process === 'object' && typeof process.nextTick === 'function'){ process.nextTick(func) } else if(typeof MutationObserver === 'function'){ const observer = new MutationObserver(func) const textNode = document.createTextNode('') observer.observe(textNode, {characterData: true}) textNode.data = 'test' } else { setTimeout(func, 0); } } #runOne(callback, resolve, reject){ this.#runMicroTask(() => { if(typeof callback !== 'function'){ const settled = this.#state === FULFILLED ? resolve : reject settled(this.#result) return } try{ const data = callback(this.#result) if(this.#isPromiseLike(data)){ data.then(resolve, reject) } else { resolve(data) } } catch (err) { reject(err) } }) } #run(){ if(this.#state === PENDING) return while(this.#handlers.length){ const {onFulfilled, onRejected, resolve, reject} = this.#handlers.shift() if(this.#state === FULFILLED){ this.#runOne(onFulfilled, resolve, reject) } else if(this.#state === REJECTED){ this.#runOne(onRejected, resolve, reject) } } } constructor(executor) { const resolve = (data) => { this.#changeState(FULFILLED, data) } const reject = (reason) => { this.#changeState(REJECTED, reason) } try { executor(resolve, reject) } catch (err) { reject(err) } } then(onFulfilled, onRejected){ return new MyPromise((resolve, reject) => { this.#handlers.push({ onFulfilled, onRejected, resolve, reject }) this.#run() }) } }
const p = new MyPromise((resolve, reject) => { setTimeout(()=>resolve(12), 1000); }) p.then(result => console.log(result), err => console.log(err)) p.then(result => { console.log(result) return new MyPromise((resolve, reject) => { setTimeout(()=>resolve(24), 1000); }) }, err => console.log(err)) .then(result => console.log(result))
|