PromiseA+ 规范
应用场景: 定时器,请求
function a (time){ return new Promise(resolve => { setTimeout(resolve, 1000) }) }
规范的定义
- promise 是一个有then方法的对象或者函数,行为遵循本规则
- thenable 是一个有then方法的函数或者对象
- value, promise 状态成功时候的值, resolve的参数,number boolean undefined, promise
- reason, promise 状态失败的值, reject的参数, 表示各种拒绝的原因
- exception 异常值
规范
Promise States
有三种状态
-
pending
1.1 初始状态, 可改变 1.2 一个Promise 在resolve/reject 之前都处于这个状态 1.3 resolve: pending -> fulfilled 状态 1.4 reject: pending -> rejected 状态
-
fulfilled
2.1 最终态,不可变 2.2 一个 Promise 被 resolve 后会变成这个状态 2.3 必须拥有一个 value 值
-
rejected
3.1 最终态,不可变 3.2 一个 Promise 被 reject 后会变成这个状态 3.3 必须拥有一个 reason 值
Tips: 总结一下, 就是promise的状态流转是这样的
pending -> resolve(value) -> fulfilled
pending -> reject(reason) -> rejected
- then promise应该提供一个then方法, 用来访问最终的结果, 无论是value还是reason.
promise.then(onFulfilled, onRejected)
4.1 参数要求
1.1 onFulfilled 必须是函数类型, 如果不是函数, 应该被忽略.
1.2 onRejected 必须是函数类型, 如果不是函数, 应该被忽略.
4.2 onFulfilled 特性
2.1 在promise变成 fulfilled 时,应该调用 onFulfilled, 参数是value
2.2 在promise变成 fulfilled 之前, 不应该被调用.
2.3 只能被调用一次(所以在实现的时候需要一个变量来限制执行次数)
4.3 onRejected 特性
3.1 在promise变成 rejected 时,应该调用 onRejected, 参数是reason
3.2 在promise变成 rejected 之前, 不应该被调用.
3.3 只能被调用一次(所以在实现的时候需要一个变量来限制执行次数)
4.4 onFulfilled 和 onRejected 应该是微任务 4.5 then方法可以被调用多次
下面来一步步实现一个Promise
1. 初始化 class
class APromise {
constructor(){
}
}
2. 定义三种状态类型
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
3. 设置初始状态
class APromise {
constructor(){
this.status = PENDING;
this.value;
this.reason;
}
}
4. 定义 resolve / reject 方法
4.1 resolve / reject 改变状态 更改status, pending -> fulfilled / rejected 4.2 两个函数的入参 value/reason
class APromise {
constructor(){
this.status = PENDING;
this.value;
this.reason;
}
resolve(value){
if(this.status === PENDING){
this.status = FULFILLED;
this.value = value;
}
}
reject(reason){
if(this.status === PENDING){
this.status = REJECTED;
this.reason = reason;
}
}
}
5. promise 构造函数的入参
5.1 promise 中接受一个执行器函数 executor(接受 resolve reject 这两个函数作为参数) 举例
console.log(1)
new Promise((resolve, reject) => {
console.log(2)
}).then(() =>{
console.log(3)
})
1
2
3
5.2 new Promise 的时候,就要执行这个函数,并且有任何错误都要被reject
class APromise {
constructor(executor){
this.status = PENDING;
this.value;
this.reason;
try{
executor(this.resolve.bind(this), this.reject.bind(this)) // 立即执行
} catch (e) {
this.reject(e)
}
}
resolve(value){
if(this.status === PENDING){
this.status = FULFILLED;
this.value = value;
}
}
reject(reason){
if(this.status === PENDING){
this.status = REJECTED;
this.reason = reason;
}
}
}
6. then方法
6.1 then 方法接收两个参数,成功回调(onFulfilled)和 失败回调(onRejected) PS: 这两个值也可以不传
then(onFulfilled, onRejected) {}
6.2 检查并处理参数, 之前提到的如果不是function, 就忽略. 这个忽略指的是原样返回value或者reason.
isFunction(param) {
return typeof param === 'function';
}
then(onFulfilled, onRejected) {
const realOnFulfilled = this.isFunction(onFulfilled)
? onFulfilled
: (value) => value
const realOnRejected = this.isFunction(onRejected)
? onRejected
: (err) => { throw err }
}
6.3 根据当前promise的状态, 判断执行哪个回调
then(onFulfilled, onRejected) {
const realOnFulfilled = this.isFunction(onFulfilled)
? onFulfilled
: (value) => value
const realOnRejected = this.isFunction(onRejected)
? onRejected
: (err) => { throw err }
if (this.status === FULFILLED) {
realOnFulfilled(this.value);
}
if (this.status === REJECTED) {
realOnRejected(this.reason)
}
}
6.4 PS: .then的返回值整体是一个promise, 我们也可以可以先用promise来包裹一下
then(onFulfilled, onRejected) {
const realOnFulfilled = this.isFunction(onFulfilled)
? onFulfilled
: (value) => value
const realOnRejected = this.isFunction(onRejected)
? onRejected
: (err) => { throw err }
const promise2 = new APromise((resolve, reject) => {
if (this.status === FULFILLED) {
realOnFulfilled(this.value);
}
if (this.status === REJECTED) {
realOnRejected(this.reason)
}
})
return promise2
}
完整代码实现
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class APromise {
constructor(executor){
this.status = PENDING;
this.value;
this.reason;
try{
executor(this.resolve.bind(this), this.reject.bind(this)) // 立即执行
} catch (e) {
this.reject(e)
}
}
resolve(value){
if(this.status === PENDING){
this.status = FULFILLED;
this.value = value;
}
}
reject(reason){
if(this.status === PENDING){
this.status = REJECTED;
this.reason = reason;
}
}
then(onFulfilled, onRejected) {
const realOnFulfilled = this.isFunction(onFulfilled)
? onFulfilled
: (value) => value
const realOnRejected = this.isFunction(onRejected)
? onRejected
: (err) => { throw err }
const promise2 = new APromise((resolve, reject) => {
if (this.status === FULFILLED) {
realOnFulfilled(this.value);
}
if (this.status === REJECTED) {
realOnRejected(this.reason)
}
})
return promise2
}
isFunction(param) { // 判断是不是函数
return typeof param === 'function'
}
}
验证一下
const p = new APromise((resolve, reject) => {
console.log('executor 请说出你的选择')
resolve('中奖了~')
reject('再接再厉~')
})
// 状态
p.then((val) => {
console.log('成功', val)
}, (err) => {
console.log('失败', err)
})
6.5 以上实现的是一个同步操作的promise, 如果在 executor()中传入一个异步操作
验证一下
new APromise ((resolve, reject) =>{
setTimeout(() => {
resolve('123123')
}, 1000);
}).then((res) =>{
console.log('res', res)
}, (err) =>{
console.log('err',err)
})
执行后发现,promise 没有任何返回 PS: 因为 promise 调用 then 方法时,当前的 promise 并没有成功,一直处于 pending 状态。所以如果当调用 then 方法时,当前状态是 pending,我们需要一个状态的监听机制, 当状态变成fulfilled或者rejected后, 再去执行callback
6.5.1 首先要拿到所有的callback, 然后才能在某个时机去执行他. 新建两个数组, 先将成功和失败的回调分别存放起来, 调用then的时候, 如果还是pending就存入数组.
this.ON_FULFILLED_CALLBACK_LIST = [];
this.ON_REJECT_CALLBACK_LIST = [];
then(onFulfilled, onRejected){
const realOnFulfilled = this.isFunction(onFulfilled)
? onFulfilled
: (value) => value
const realOnRejected = this.isFunction(onRejected)
? onRejected
: (err) => { throw err }
const promise2 = new APromise((resolve, reject) => {
if (this.status === FULFILLED) {
realOnFulfilled(this.value);
}
if (this.status === REJECTED) {
realOnRejected(this.reason)
}
// 当Promise 里面有异步请求控制状态时,会先走到then 方法里面
// 把成功的回调和失败的回调先存储起来, 等到异步请求回来后变更状态,再触发执行
if (this.status === PENDING){
// 如果promise的状态是 pending,需要将 onFulfilled 和 onRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行
this.ON_FULFILLED_CALLBACK_LIST.push(realOnFulfilled)
// this.ON_FULFILLED_CALLBACK_LIST.push(() => {
// realOnFulfilled(this.value)
// })
// 如果promise的状态是 pending,需要将 onFulfilled 和 onRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行
this.ON_REJECT_CALLBACK_LIST.push(realOnRejected)
// this.ON_REJECT_CALLBACK_LIST.push(() => {
// realOnRejected(this.reason)
// })
}
});
return promise2
}
6.5.2 在status发生变化的时候, 就执行所有的回调,可以在resolve/ reject 里面直接去写
resolve(value) {
if (this.status === PENDING) {
// 状态由 pending 变成成功 fulfilled
this.status = FULFILLED;
this.value = value;
this.ON_FULFILLED_CALLBACK_LIST.forEach(callback => {
callback(this.value)
// callback()
});
}
}
reject(reason) {
if (this.status === PENDING) {
// 状态由 pending 变成成功 rejected
this.status = REJECTED;
this.reason = reason;
this.ON_REJECT_CALLBACK_LIST.forEach(callback => {
callback(this.reason)
// callback()
});
}
}
完整代码
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class APromise {
constructor(executor){
this.status = PENDING;
this.value;
this.reason;
this.ON_FULFILLED_CALLBACK_LIST = [];
this.ON_REJECT_CALLBACK_LIST = [];
try{
// 立即执行
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (e) {
this.reject(e)
}
}
resolve(value) {
if (this.status === PENDING) {
// 状态由 pending 变成成功 fulfilled
this.status = FULFILLED;
this.value = value;
this.ON_FULFILLED_CALLBACK_LIST.forEach(callback => {
callback(this.value)
// callback()
});
}
}
reject(reason) {
if (this.status === PENDING) {
// 状态由 pending 变成成功 rejected
this.status = REJECTED;
this.reason = reason;
this.ON_REJECT_CALLBACK_LIST.forEach(callback => {
callback(this.reason)
// callback()
});
}
}
then(onFulfilled, onRejected){
const realOnFulfilled = this.isFunction(onFulfilled)
? onFulfilled
: (value) => value
const realOnRejected = this.isFunction(onRejected)
? onRejected
: (err) => { throw err }
const promise2 = new APromise((resolve, reject) => {
if (this.status === FULFILLED) {
realOnFulfilled(this.value);
}
if (this.status === REJECTED) {
realOnRejected(this.reason)
}
// 当Promise 里面有异步请求控制状态时,会先走到then 方法里面
// 把成功的回调和失败的回调先存储起来, 等到异步请求回来后变更状态,再触发执行
if (this.status === PENDING){
// 如果promise的状态是 pending,需要将 onFulfilled 和 onRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行
this.ON_FULFILLED_CALLBACK_LIST.push(realOnFulfilled)
// this.ON_FULFILLED_CALLBACK_LIST.push(() => {
// realOnFulfilled(this.value)
// })
// 如果promise的状态是 pending,需要将 onFulfilled 和 onRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行
this.ON_REJECT_CALLBACK_LIST.push(realOnRejected)
// this.ON_REJECT_CALLBACK_LIST.push(() => {
// realOnRejected(this.reason)
// })
}
});
return promise2
}
isFunction(param) { // 判断是不是函数
return typeof param === 'function'
}
}
验证一下
new APromise((resolve, reject) => {
setTimeout(() => {
resolve('123123')
}, 1000);
}).then((res) => {
console.log('res', res)
}, (err) => {
console.log('err', err)
})
7. then 的链式调用&值穿透特性
1. promise 的优势在于可以链式调用。在我们使用 Promise 的时候,当 then 函数中 return 了一个值,不管是什么值,我们都能在下一个 then 中获取到,这就是then 的链式调用;
2. 如果我们不在 then 中放入参数,例:promise.then().then(),那么其后面的 then 依旧可以得到之前 then 返回的值,这就是所谓的值的穿透;
PS:结合 PromiseA+ 规范, 简单梳理 (此处参考:https://juejin.cn/post/6850037281206566919#heading-5)
1. then 的参数 onFulfilled 和 onRejected 可以缺省,如果 onFulfilled 或者 onRejected不是函数,将其忽略,且依旧可以在下面的 then 中获取到之前返回的值 「规范 Promise/A+ 2.2.1、2.2.1.1、2.2.1.2」
2. promise 可以 then 多次,每次执行完 promise.then 方法后返回的都是一个“新的promise" 「规范 Promise/A+ 2.2.7」
3. 如果 then 的返回值 x 是一个普通值,那么就会把这个结果作为参数,传递给下一个 then 的成功的回调中;
4. 如果 then 中抛出了异常,那么就会把这个异常作为参数,传递给下一个 4. then 的失败的回调中;「规范 Promise/A+ 2.2.7.2」
5. 如果 then 的返回值 x 是一个 promise,那么会等这个 promise 执行完,promise 如果成功,就走下一个 then 的成功;如果失败,就走下一个 then 的失败;如果抛出异常,就走下一个 then 的失败;「规范 Promise/A+ 2.2.7.3、2.2.7.4」
6. 如果 then 的返回值 x 和 promise 是同一个引用对象,造成循环引用,则抛出异常,把异常传递给下一个 then 的失败的回调中; 「规范 Promise/A+ 2.3.1」
7. 如果 then 的返回值 x 是一个 promise,且 x 同时调用 resolve 函数和 reject 函数,则第一次调用优先,其他所有调用被忽略;「规范 Promise/A+ 2.3.3.3.3」
7.1 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e。(这样的话, 我们就需要手动catch代码,遇到报错就reject)
```js
const fulfilledMicrotask = () => {
try{
realOnFulfilled(this.value)
}catch (e) {
reject(e)
}
}
const rejectedMicrotask = () => {
try {
realOnFulfilled(this.value)
} catch (e) {
reject(e)
}
}
```
7.2 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值
7.3 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因。
需要注意的是,如果promise1的onRejected执行成功了,promise2应该被resolve
```js
const realOnFulfilled = this.isFunction(onFulfilled)
? onFulfilled
: (value) => value
const realOnRejected = this.isFunction(onRejected)
? onRejected
: (err) => { throw err }
```
7.4 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行resolvePromise方法
```js
then(onFulfilled, onRejected){
// 解决 onFulfilled,onRejected 没有传值的问题
// 7.2 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值
// 7.3 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因。
const realOnFulfilled = this.isFunction(onFulfilled)
? onFulfilled
: (value) => value
const realOnRejected = this.isFunction(onRejected)
? onRejected
: (err) => { throw err }
// 每次调用 then 都返回一个新的 promise
const promise2 = new APromise((resolve, reject) => {
const fulfilledMicrotask = () => {
// 1. 由于原生的 Promise 是V8引擎提供的微任务 这里使用mutationObserver 来实现微任务
// 2. queueMicrotask也可以实现微任务机制,queueMicrotask 兼容性不是很好,IE 下完全不支持, 由于queueMicrotask 的 polyfill 是基于 promise 实现的,如果不支持 promise 会转成 setTimeout
// 3. 也可以使用setTimeout 模拟异步,不过使用 setTimeout 在这里是宏任务
mutationObserver(() =>{
try{
const x = realOnFulfilled(this.value)
// x可能是一个promise
this.resolvePromise(promise2, x, resolve, reject)
}catch (e) {
reject(e)
}
})
}
const rejectedMicrotask = () => {
mutationObserver(() => {
try {
const x = realOnFulfilled(this.reason)
this.resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
if (this.status === FULFILLED) {
realOnFulfilled(this.value);
}
if (this.status === REJECTED) {
realOnRejected(this.reason)
}
// 当Promise 里面有异步请求控制状态时,会先走到then 方法里面
// 把成功的回调和失败的回调先存储起来, 等到异步请求回来后变更状态,再触发执行
if (this.status === PENDING){
// 如果promise的状态是 pending,需要将 onFulfilled 和 onRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行
this.ON_FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask)
// this.ON_FULFILLED_CALLBACK_LIST.push(() => {
// realOnFulfilled(this.value)
// })
// 如果promise的状态是 pending,需要将 onFulfilled 和 onRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行
this.ON_REJECT_CALLBACK_LIST.push(rejectedMicrotask)
// this.ON_REJECT_CALLBACK_LIST.push(() => {
// realOnRejected(this.reason)
// })
}
});
return promise2
}
```
7.5 实现resolvePromise
```js
resolvePromise(promise2, x, resolve, reject) {
// 如果 newPromise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 newPromise
// 这是为了防止死循环
if (promise2 === x){
return reject(new TypeError('The promise and the return value are the same'))
}
if(x instanceof APromise){
// 如果 x 为 Promise ,则使 newPromise 接受 x 的状态
// 也就是继续执行x,如果执行的时候拿到一个y,还要继续解析y
setTimeout(() => {
x.then(
(y) =>{ // 接收新的值y
this.resolvePromise(promise2, y, resolve, reject)
},
reject
)
})
} else if (typeof x === 'object' && x != null || this.isFunction(x)){
let then = null;
try{
// 把 x.then 赋值给 then
then = x.then;
}catch (e) {
// 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
return reject(e)
}
// 如果 then 是函数
if (isFunction(x)) {
// 后续的条件要严格判断 保证代码能和别的库一起使用,约定执行次数
let called = false;
// 将 x 作为函数的作用域 this 调用
// 传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise
try {
then.call( // 根据 promise 的状态决定是成功还是失败
x,
(y) => {
// 如果 resolvePromise 以值 y 为参数被调用,则运行 resolvePromise
if (called) {
return;
}
// 需要有一个变量called来保证只调用一次.
called = true;
// 递归解析的过程(因为可能 promise 中还有 promise)
this.resolvePromise(promise2, y, resolve, reject)
},
// 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
(r) =>{
if (called) {
return;
}
called = true;
reject(r) // 失败之后就reject
}
)
} catch (err) {
// 如果调用 then 方法抛出了异常 e:
if (called) {
return;
}
// 否则以 e 为据因拒绝 promise
reject(err)
}
} else {
// 如果 then 不是函数,以 x 为参数执行 promise
resolve(x)
}
} else {
// 如果 x.then 是个普通值就直接返回 resolve 作为结果
resolve(x)
}
}
```
完整代码
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class APromise {
constructor(executor){
this.status = PENDING;
this.value;
this.reason;
this.ON_FULFILLED_CALLBACK_LIST = [];
this.ON_REJECT_CALLBACK_LIST = [];
try{
// 立即执行
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (e) {
this.reject(e)
}
}
resolve(value) {
if (this.status === PENDING) {
// 状态由 pending 变成成功 fulfilled
this.status = FULFILLED;
this.value = value;
this.ON_FULFILLED_CALLBACK_LIST.forEach(callback => {
callback(this.value)
// callback()
});
}
}
reject(reason) {
if (this.status === PENDING) {
// 状态由 pending 变成成功 rejected
this.status = REJECTED;
this.reason = reason;
this.ON_REJECT_CALLBACK_LIST.forEach(callback => {
callback(this.reason)
// callback()
});
}
}
then(onFulfilled, onRejected){
// 解决 onFulfilled,onRejected 没有传值的问题
// 7.2 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值
// 7.3 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因。
const realOnFulfilled = this.isFunction(onFulfilled)
? onFulfilled
: (value) => value
const realOnRejected = this.isFunction(onRejected)
? onRejected
: (err) => { throw err }
// 每次调用 then 都返回一个新的 promise
const promise2 = new APromise((resolve, reject) => {
const fulfilledMicrotask = () => {
setTimeout(() =>{
try{
const x = realOnFulfilled(this.value)
// x可能是一个promise
this.resolvePromise(promise2, x, resolve, reject)
}catch (e) {
reject(e)
}
})
}
const rejectedMicrotask = () => {
setTimeout(() => {
try {
const x = realOnFulfilled(this.reason)
this.resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
if (this.status === FULFILLED) {
realOnFulfilled(this.value);
}
if (this.status === REJECTED) {
realOnRejected(this.reason)
}
// 当Promise 里面有异步请求控制状态时,会先走到then 方法里面
// 把成功的回调和失败的回调先存储起来, 等到异步请求回来后变更状态,再触发执行
if (this.status === PENDING){
// 如果promise的状态是 pending,需要将 onFulfilled 和 onRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行
this.ON_FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask)
// this.ON_FULFILLED_CALLBACK_LIST.push(() => {
// realOnFulfilled(this.value)
// })
// 如果promise的状态是 pending,需要将 onFulfilled 和 onRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行
this.ON_REJECT_CALLBACK_LIST.push(rejectedMicrotask)
// this.ON_REJECT_CALLBACK_LIST.push(() => {
// realOnRejected(this.reason)
// })
}
});
return promise2
}
resolvePromise(promise2, x, resolve, reject) {
// 如果 newPromise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 newPromise
// 这是为了防止死循环
if (promise2 === x){
return reject(new TypeError('The promise and the return value are the same'))
}
if(x instanceof APromise){
// 如果 x 为 Promise ,则使 newPromise 接受 x 的状态
// 也就是继续执行x,如果执行的时候拿到一个y,还要继续解析y
setTimeout(() => {
x.then(
(y) =>{ // 接收新的值y
this.resolvePromise(promise2, y, resolve, reject)
},
reject
)
})
} else if (typeof x === 'object' && x != null || this.isFunction(x)){
let then = null;
try{
// 把 x.then 赋值给 then
then = x.then;
}catch (e) {
// 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
return reject(e)
}
// 如果 then 是函数
if (isFunction(x)) {
// 后续的条件要严格判断 保证代码能和别的库一起使用,约定执行次数
let called = false;
// 将 x 作为函数的作用域 this 调用
// 传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise
try {
then.call( // 根据 promise 的状态决定是成功还是失败
x,
(y) => {
// 如果 resolvePromise 以值 y 为参数被调用,则运行 resolvePromise
if (called) {
return;
}
// 需要有一个变量called来保证只调用一次.
called = true;
// 递归解析的过程(因为可能 promise 中还有 promise)
this.resolvePromise(promise2, y, resolve, reject)
},
// 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
(r) =>{
if (called) {
return;
}
called = true;
reject(r) // 失败之后就reject
}
)
} catch (err) {
// 如果调用 then 方法抛出了异常 e:
if (called) {
return;
}
// 否则以 e 为据因拒绝 promise
reject(err)
}
} else {
// 如果 then 不是函数,以 x 为参数执行 promise
resolve(x)
}
} else {
// 如果 x.then 是个普通值就直接返回 resolve 作为结果
resolve(x)
}
}
isFunction(param) { // 判断是不是函数
return typeof param === 'function'
}
}
代码验证
const test = new APromise((resolve, reject) => {
setTimeout(() => {
resolve('123123 中奖了~')
}, 1000);
}).then((res) => {
console.log('res', res)
}, (err) => {
console.log('err', err)
})
console.log(test)
setTimeout(() => {
console.log('20000', test)
}, 2000);
8. 关于 onFulfilled 和 onRejected 是微任务
8.1 由于原生的 Promise 是V8引擎提供的微任务 这里可以使用mutationObserver 来实现微任务
8.2 queueMicrotask也可以实现微任务机制,queueMicrotask 兼容性不是很好,IE 下完全不支持, 由于 queueMicrotask 的 polyfill 是基于 promise 实现的,如果不支持 promise 会转成 setTimeout
8.3 也可以使用 setTimeout 模拟异步,不过使用 setTimeout 在这里是宏任务
const fulfilledMicrotask = () => {
setTimeout(() =>{
try{
const x = realOnFulfilled(this.value)
// x可能是一个promise
this.resolvePromise(promise2, x, resolve, reject)
}catch (e) {
reject(e)
}
})
}
const rejectedMicrotask = () => {
setTimeout(() => {
try {
const x = realOnFulfilled(this.reason)
this.resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
9. Promise 的 API
9.1 Promise.prototype.catch()
catch(onRejected) {
return this.then(null, onRejected);
}
APromise.prototype.catch = function (errCallback) {
return this.then(null, errCallback)
}
验证
APromise.prototype.catch = function (errCallback) {
return this.then(null, errCallback)
}
const test = new APromise((resolve, reject) => {
setTimeout(() => {
// resolve('123123 中奖了~')
reject('555555')
}, 1000);
}).then((val) => {
console.log(`[then value is ${val}]`)
}).catch((err) =>{
console.log(`[catch reason is ${err}]`)
})
9.2 Promise.resolve()
现有对象转为Promise对象,如果 Promise.resolve 方法的参数,不是具有 then 方法的对象(又称 thenable 对象),则返回一个新的 Promise 对象,且它的状态为fulfilled 注意这是一个静态方法, 因为咱们是通过Promise.resolve调用的, 而不是通过实例去调用的
static resolve(value) {
if (value instanceof APromise) {
return value;
}
return new APromise((resolve) => {
resolve(value);
});
}
验证一下
APromise.resolve(new APromise((resolve, reject) => {
setTimeout(() => {
resolve('ok');
}, 3000);
})).then(val => {
console.log(val, 'success')
}).catch(err => {
console.log(err, 'error')
})
9.3 Promise.reject()
返回一个新的Promise实例,该实例的状态为rejected。Promise.reject方法的参数reason,会被传递给实例的回调函数。
static reject(reason) {
return new APromise((resolve, reject) => {
reject(reason);
});
}
验证一下
APromise.reject(123).then(val => {
console.log(val, 'success')
}).catch(err => {
console.log(err, 'error')
})
9.4 Promise.all()
promise.all 是解决并发问题的,多个异步并发获取最终的结果(如果有一个失败则失败)
APromise.all = function (values) {
if (!Array.isArray(values)) {
const type = typeof values;
return new TypeError(`TypeError: ${type} ${values} is not iterable`)
}
return new APromise((resolve, reject) => {
let resultArr = [];
let orderIndex = 0;
const processResultByKey = (value, index) => {
resultArr[index] = value;
if (++orderIndex === values.length) {
resolve(resultArr)
}
}
for (let i = 0; i < values.length; i++) {
let value = values[i];
if (value && typeof value.then === 'function') {
value.then((value) => {
processResultByKey(value, i);
}, reject);
} else {
processResultByKey(value, i);
}
}
});
}
验证
let k1 = new APromise((resolve, reject) => {
setTimeout(() => {
resolve('k1');
}, 1000);
})
let k2 = new APromise((resolve, reject) => {
setTimeout(() => {
reject('k2');
}, 1000);
})
APromise.all([1,2,3,k1,k2]).then(val => {
console.log('resolve', val);
}, err => {
console.log('reject', err);
})
9.5 Promise.race()
const p = Promise.race([p1, p2, p3]);
该方法是将多个 Promise 实例,包装成一个新的 Promise 实例。 只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数 用来处理多个请求,采用最快的(谁先完成用谁的)
static race(promiseList) {
return new APromise((resolve, reject) => {
const length = promiseList.length;
if (length === 0) {
return resolve();
} else {
for (let i = 0; i < length; i++) {
APromise.resolve(promiseList[i]).then(
(value) => {
return resolve(value);
},
(reason) => {
return reject(reason);
});
}
}
});
}
验证一下
const t1 = new APromise((resolve, reject) => {
setTimeout(() => {
resolve(111);
}, 1000);
});
const t2 = new APromise((resolve, reject) => {
setTimeout(() => {
resolve(222);
}, 2000);
});
const t3 = new APromise((resolve, reject) => {
setTimeout(() => {
resolve(333);
}, 3000);
});
APromise.race([t1, t2, t3]).then(console.log);
PS: Promise 是没有中断方法的,xhr.abort()、ajax 有自己的中断方法,axios 是基于 ajax 实现的;fetch 基于 promise,所以他的请求是无法中断的 promise 存在的缺陷,我们可以使用 race 来自己封装中断方法
function wrap(promise) {
// 在这里包装一个 promise,可以控制原来的promise是成功还是失败
let abort;
let newPromise = new APromise((resolve, reject) => { // defer 方法
abort = reject;
});
let p = APromise.race([promise, newPromise]); // 任何一个先成功或者失败 就可以获取到结果
p.abort = abort;
return p;
}
const promise = new APromise((resolve, reject) => {
setTimeout(() => { // 模拟的接口调用 ajax 肯定有超时设置
resolve('成功');
}, 1000);
});
let newPromise = wrap(promise);
setTimeout(() => {
// 超过3秒 就算超时 应该让 proimise 走到失败态
newPromise.abort('超时了');
}, 3000);
newPromise.then((val => {
console.log(`[success is val = ${val}]`)
})).catch(err => {
console.log(`[reject is val = ${err}]`)
})
小结
关于 Promise 规范&应用就复习到这里,感谢指正 ~~
参考文章:
Promises/A+