Promise原理、方法及手写
ES6Promise对象:Promise 对象 - ECMAScript 6入门 (ruanyifeng.com)
Promise/A+链接:Promises/A+ (promisesaplus.com)
什么是Promise?
Promise是异步编程的一种解决方案,代表一个异步操作的最终完成或者失败。
Promise的三种状态
一个Promise必然会处于以下三种状态之一:
- 未完成(pending):初始状态,即没有成功,也没有失败。
- 成功(fufilled):表示异步操作成功。
- 失败(rejected):表示异步操作失败。
Promise的状态由异步操作的结果来决定,当状态发生改变时,就无法再次改变。
Promise的状态只能从未完成(pending)转变成成功(fufilled)或者是从未完成(pending)转变成失败(rejected)。
基本用法
Promise对象是一个构造函数,通过new Promise来创建实例对象
const promise = new Promise((resolve, reject) => {
// some code
if(/*判断条件*/) {
resolve(res) // res为成功的结果
} else {
reject(err) // err为失败的原因
}
})
Promise构造函数接收一个回调函数作为参数,该函数的两个参数分别为resolve和reject。
resolve函数的作用是将Promise对象的状态从"未完成"变成"成功",在异步操作完成时进行调用,并将异步操作的结果,作为参数传递出去。
reject函数的作用是将Promise对象的状态从"未完成"变成"失败",在异步操作完成时进行调用,并将异步操作的结果,作为参数传递出去。
Promise.then()
Promise实例具有then方法,该方法的第一个参数是成功状态下的回调函数,第二个参数是失败状态下的回调函数,同时该方法返回的是一个新的Promise实例。
当Promise实例的状态为成功时,则不会调用then方法中失败的回调函数。
const promise = new Promise((resolve, reject) => {
resolve(1)
}).then(
(res) => { console.log(res) },
(err) => { console.log(err) }
)
// 打印结果为1
非链式调用的then,可以对同一个Promise实例可以多次调用then方法。
const promise = new Promise((resolve, reject) => {
resolve(1)
})
promise.then(
(res) => { console.log(res) }
)
promise.then(
(res) => { console.log(res) }
)
/*
打印结果为
1
1
*/
链式调用的then,then方法默认返回的是Promise对象,所以在then方法后还可以继续使用then方法。
第一个then方法的回调函数执行完成后,会继续执行第二个then方法的回调函数。
const promise = new Promise((resolve, reject) => {
resolve()
}).then(
(res) => { console.log(1) }
).then(
(res) => { console.log(2) }
)
/*
打印结果为
1
2
*/
当第一个then方法不返回或者返回的是一个非thenable对象时,返回的值都只能在下一次then方法的成功回调中接收。
const promise = new Promise((resolve, reject) => {
reject()
}).then(
(res) => { },
(err) => 1
).then(
(res) => { console.log(res) }
)
// 打印结果为 1
thenable对象:
- Promise
- { then()
- function a(){} a.then = function(){}
具有then方法为thenable对象
当第一个then方法返回是一个thenable对象时,第二个then方法会等第一个then方法返回的thenable对象状态发生改变时,再去执行回调函数。如果状态为fufilled时,会调用第一个回调函数,如果状态为rejected时,会调用第二个回调函数。
const promise = new Promise((resolve, reject) => {
resolve()
}).then(
(res) => new Promise((resolve, reject) => {
reject()
}),
).then(
(res) => { console.log(1) },
(err) => { console.log(2) }
)
// 打印结果为 2
Promise.catch()
Promise实例具有catch方法,当实例失败时会调用该方法的回调函数,与then方法中的第二个回调方法效果一致。如果then方法指定的回调函数发生错误,也会被捕获。
const promise = new Promise((resolve, reject) => {
reject()
}).then(
(res) => { }
).catch(
(err) => { console.log(1) }
)
const promise = new Promise((resolve, reject) => {
resolve()
}).then(
(res) => new Promise((resolve, reject) => {
reject()
})
).catch(
(err) => { console.log(1) }
)
// 打印结果均为 1
Promise.finally()
finally方法用于不管Promise实例对象最后的状态如何,都会执行回调函数。
finally方法的回调函数不接收任何参数,所以无法从finally方法中判断promise实例的状态是fufilled还是rejected。
const promise = new Promise((resolve, reject) => {
resolve()
}).then(
(res) => { console.log(1) }
).finally(
() => { console.log(2) }
)
const promise = new Promise((resolve, reject) => {
reject()
}).then(
(res) => { },
(err) => { console.log(1) }
).finally(
() => { console.log(2) }
)
/*
打印结果均为
1
2
*/
Promise.all()
Promise.all()方法接收一个可迭代(数组或字符串)的Promise实例,其内部元素也可以是Promise实例,也可以不是。如果传入的Promise实例的状态都为fufilled,那么返回的是一个数组,数组中的元素分别为成功的结果。如果传入的Promise实例的状态有一个为rejected,那么返回的是第一个失败的结果。
成功的情况下,输入的数组元素与输出的数组元素一一对应,输入的数组的第一个元素的结果为输出的数组的第一个元素。如果数组中存在异步操作,会等待异步操作完成后在输出结果。
const promise1 = 1
const promise2 = new Promise((resolve) => {
setTimeout(() => {
resolve(2)
}, 1000)
})
const promise3 = Promise.resolve(3)
const promise = [promise1, promise2, promise3]
Promise.all(promise).then(res => {
console.log(res);
})
// 打印结果为 [1, 2, 3]
const promise1 = 1
const promise2 = new Promise((resolve, reject) => { throw new Error('报错了') })
const promise3 = Promise.resolve(3)
const promise = [promise1, promise2, promise3]
Promise.all(promise).then(res => {
console.log(res);
})
// 打印结果为 Error: 报错了
Promise.race()
Promise.race()方法和Promise.all()方法一样接收的都是一个可迭代的实例,此方法并不会返回全部的结果,只会返回第一个成功或者失败的结果,其他效果和Promise.all()方法一样。
const promise1 = 1
const promise2 = new Promise((resolve) => {
setTimeout(() => {
resolve(2)
}, 1000)
})
const promise = [promise1, promise2]
Promise.race(promise).then(res => {
console.log(res);
})
// 打印结果为 1
const promise1 = Promise.reject(1)
const promise2 = new Promise((resolve) => {
setTimeout(() => {
resolve(2)
}, 1000)
})
const promise = [promise1, promise2]
Promise.race(promise).then(res => {
console.log(res);
})
// 打印结果为 Uncaught (in promise) 1
Promise.allSettled()
Promise.allSettled()方法传入的也是一个可以迭代的promise实例,此方法不论结果为fufilled和rejected都会把结果和状态返回。
const promise1 = 1
const promise2 = new Promise((resolve) => {
setTimeout(() =1> {
resolve(2)
}, 1000)
})
const promise3 = Promise.reject(3)
const promise = [promise1, promise2, promise3]
Promise.allSettled(promise).then(res => {
console.log(res);
})
/*
打印结果为
(3) [{…}, {…}, {…}]
0: {status: 'fulfilled', value: 1}
1: {status: 'fulfilled', value: 2}
2: {status: 'rejected', reason: 3}
*/
Promise.any()
Promise.any()方法和Promise.race()方法很像,也是输出最快的结果,但是并不会因为某一个Promise实例的状态为rejected而结束,当所有的Promise实例的状态都为rejected时才会结束。
const promise1 = 1
const promise2 = new Promise(resolve => {
setTimeout(() => {
resolve(2)
}, 1000)
})
const promise3 = Promise.resolve(3)
const promise = [promise1, promise2, promise3]
Promise.any(promise).then(res => {
console.log(res);
})
// 打印结果为 1
const promise1 = Promise.reject(1)
const promise2 = new Promise(resolve => {
setTimeout(() => {
resolve(2)
}, 1000)
})
const promise3 = Promise.reject(3)
const promise = [promise1, promise2, promise3]
Promise.any(promise).then(res => {
console.log(res);
})
// 打印结果为 2
const promise1 = Promise.reject(1)
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(2)
}, 1000)
})
const promise3 = Promise.reject(3)
const promise = [promise1, promise2, promise3]
Promise.any(promise).then(res => {
console.log(res);
})
// 打印结果为 Uncaught (in promise) AggregateError: All promises were rejected
Promise.resolve()
Promise.resolve()方法是把现有元素转换成状态为fulfilled的Promise实例,
Promise.resolve(1)
// 等价于
new Promise(resolve => resolve(1))
(1)当参数是一个 Promise 实例
如果参数是 Promise 实例,那么Promise.resolve()方法将不做任何修改、原封不动地返回这个实例。
const p = new Promise(resolve => { resolve(1) })
const promise = Promise.resolve(p)
console.log(promise);
/*
打印结果为
Promise {<fulfilled>: 1}
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: 1
*/
(2)当参数是一个thenable对象
如果参数是 thenable对象,Promise.resolve()方法将会把这个对象转换为Promise实例,并立即执行 thenable对象中的then方法。
const thenable = {
then: function (resolve) {
resolve(1);
}
};
const promise = Promise.resolve(thenable)
console.log(promise);
/*
打印结果为
Promise {<pending>}
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: 1
*/
(3)当参数不是thenable对象
当参数不是thenable对象是,Promise.resolve()方法会返回一个新的Promise实例,并且状态为fulfilled。
const p = 1
const promise = Promise.resolve(p)
console.log(promise);
/*
打印结果为
Promise {<fulfilled>: 1}
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: 1
*/
(4)当不带有任何参数
当参数为空时,Promise.resolve()方法会返回一个状态为fulfilled的Promise实例,使用then方法打印res时,结果为undefined。
const promise = Promise.resolve()
console.log(promise);
promise.then((res) => {
console.log(res);
})
/*
打印结果为
Promise {<fulfilled>: undefined}
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: undefined
undefined
*/
Promise.reject()
Promise.reject()方法也会返回一个新的Promise实例,并且状态为rejected。Promise.reject()方法接收的参数,会作为错误的结果,原封不动的返回,可以在后续的then方法或者catch方法中捕获。
const promise = Promise.reject("报错")
// 等同于
const promise = new Promise((resolve, reject) => { reject("报错") })
console.log(promise);
/*
打印结果为
Promise {<rejected>: '报错'}
[[Prototype]]: Promise
[[PromiseState]]: "rejected"
[[PromiseResult]]: "报错"
*/
手写Promise
// 初始的promise为pending态, resolve后promise转为fullfilled态, reject后转为rejected态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class Promise {
value = null // 成功的结果
reason = null // 失败的原因
state = PENDING // 状态
// 保存异步的回调
onFulfilledCallbacks = []
onRejectedCallbacks = []
constructor(executor) {
// 成功的回调
const resolve = (value) => {
// 判断是否从初始状态开始改变
if (this.state === PENDING) {
// 改变状态
this.state = FULFILLED
// 保存成功的结果
this.value = value
// 调用then函数的回调函数(发布)
this.onFulfilledCallbacks.forEach(cb => cb())
}
}
// 失败的回调
const reject = (reason) => {
// 判断是否从初始状态开始改变
if (this.state === PENDING) {
// 改变状态
this.state = REJECTED
// 保存失败的原因
this.reason = reason
// 调用then函数的回调函数(发布)
this.onRejectedCallbacks.forEach(cb => cb())
}
}
// 捕获回调函数中的错误
try {
// Promise中的回调函数
executor(resolve, reject)
} catch (error) {
// 报错时改变状态并抛出错误
reject(error)
}
}
then(onFulfilled, onRejected) {
/*
当then方法不执行resolve或reject函数就执行后面的链式调用时,回调函数则是undefined,会发生报错。
所以要在入口处添加判断,当reject不是函数时,让它变成函数并返回错误的原因,这样就会被后续的catch捕获到,就做到了异常穿透,
当resolve不是函数时,需要让它变成一个成功的回调,不需要任何操作,跳过该层即可,当有值传入时就会传出值,这便是值传递,类似异常穿透。
*/
// 判断回调函数是否为函数
if (typeof onRejected !== "function") {
onRejected = reason => {
throw reason
}
}
if (typeof onFulfilled !== "function") {
onFulfilled = value => value
}
// executor函数成功的回调
// 链式调用需要返回一个新的Promise
// 返回的Promise的状态与下一个.then相关
const promise2 = new Promise((resolve, reject) => {
if (this.state === FULFILLED) {
// then方法必须是异步任务,可以是宏任务,也可以是微任务
queueMicrotask(() => {
// 当.then报错时,需要在下一个then方法的err提示
// 使用trycatch捕获错误,发生报错时,手动设置状态为reject并抛出错误
try {
const x = onFulfilled(this.value)
// 对then方法返回的数据进行处理
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
// executor函数失败的回调
if (this.state === REJECTED) {
queueMicrotask(() => {
try {
const x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
}
// 使用发布订阅模式
// 保存executor函数中异步的结果
if (this.state === PENDING) {
// 订阅、记录
// 在非链式调用的情况下,保存每一个回调函数
// 用函数的方式进行包裹,方便进行处理
this.onFulfilledCallbacks.push(() => {
queueMicrotask(() => {
try {
const x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
})
this.onRejectedCallbacks.push(() => {
queueMicrotask(() => {
try {
const x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
})
})
}
})
return promise2
}
catch(onRejected) {
return this.then(null, onRejected)
}
finally(onFinally) {
return this.then(onFinally, onFinally)
}
all(array) {
// 保存结果
let result = []
// 判断是否全部执行
let index = 0
return new Promise((resolve, reject) => {
// 保存结果
function addData(key, value) {
// 保存相对应位置的结果
result[key] = value
// 增加长度
index++
// 如果保存结果的长度和传进来的数组长度一致,则全部完成,返回数组
if (index === array.length) resolve(result)
}
// 遍历数组
array.forEach((item, index) => {
// 保存当前项
let promise = item
// 判断当前项是否为Promise实例
if (promise instanceof Promise) {
promise.then(
// 成功保存结果
res => addData(index, res),
// 失败则直接抛出错误
rej => reject(rej)
)
} else {
// 如果不是Promise实例直接保存结果
addData(index, item)
}
})
})
}
race(array) {
return new Promise((resolve, reject) => {
// 遍历数组
array.forEach(item => {
// 保存当前项
let promise = item
// 判断当前项是否为Promise实例
if (promise instanceof Promise) {
promise.then(
// 成功返回结果
res => resolve(res),
// 失败则直接抛出错误
rej => reject(rej)
)
} else {
// 如果不是Promise实例直接返回结果
resolve(item)
}
})
})
}
allSettled(array) {
// 保存结果
let result = []
// 判断是否全部执行
let index = 0
return new Promise(resolve => {
// 保存结果
function addData(key, value, status) {
// 保存相对应位置的结果
result[key] = {
status: status,
value: value
}
// 增加长度
index++
// 如果保存结果的长度和传进来的数组长度一致,则全部完成,返回数组
if (index === array.length) resolve(result)
}
// 遍历数组
array.forEach((item, index) => {
// 保存当前项
let promise = item
// 判断当前项是否为Promise实例
if (promise instanceof Promise) {
promise.then(
// 成功保存结果
res => addData(index, res, 'fulfilled'),
// 失败则直接抛出错误
rej => addData(index, rej, 'rejected')
)
} else {
// 如果不是Promise实例直接保存结果
addData(index, item, 'fulfilled')
}
})
})
}
any(array) {
// 判断是否全部执行
let index = 0
return new Promise(resolve => {
// 判断失败的次数
function judgment() {
index++
// 如果全部失败,则抛出全部失败
if (index === array.length) resolve(new Error('All promises were rejected'))
}
// 遍历数组
array.forEach((item, index) => {
// 保存当前项
let promise = item
// 判断当前项是否为Promise实例
if (promise instanceof Promise) {
promise.then(
// 成功返回结果
res => resolve(res),
// 失败则保存当前结果
rej => judgment()
)
} else {
// 如果不是Promise实例直接返回结果
resolve(item)
}
})
})
}
}
Promise.resolve = function (value) {
return new Promise(resolve => {
// 对Promise实例进行递归处理,如果包含多层Promise实例,则返回最后一层的结果
function resolvePromise(value) {
value.then(res => {
if (res instanceof Promise) {
resolvePromise(res)
} else {
resolve(res)
}
})
}
// 对thenable对象进行递归处理,如果包含多层thenable对象,则返回最后一层的结果
function thenablePromise(value) {
if (value !== null && typeof value === 'object' || typeof value !== 'function') {
const then = value.then
// 判断then是否为函数
if (typeof then === 'function') {
// 调用then函数,拿到里面的结果
then.call(
value,
res => { thenablePromise(res) }
)
} else {
resolve(value)
}
} else {
resolve(value)
}
}
if (value instanceof Promise) {
// 判断是否为Promise实例
resolvePromise(value)
} else if (value !== null && typeof value === 'object' || typeof value !== 'function') {
// 判断是否为thenable对象
thenablePromise(value)
} else {
// 如果都不是则直接返回
resolve(value)
}
})
}
Promise.reject = function (value) {
return new Promise((resolve, reject => {
reject(value)
}))
}
function resolvePromise(promise2, x, resolve, reject) {
// If promise and x refer to the same object, reject promise with a TypeError as the reason.
// 如果promise和x指向同一个对象,则以TypeError为理由拒绝promise。
if (promise2 === x) {
reject(new TypeError('Chaining cycle detected for promise'))
}
// 判断返回是否为thenable对象
// promise, { then(){} }, function a(){} a.then = function(){}
if (x !== null && typeof x === 'object' || typeof x !== 'function') {
// 在return的thenable对象中的回调函数,可能会报错
try {
// return 是thenable对象
// 按照promise规则走
const then = x.then
// { then: 1 }, 可能存在then不是函数的情况,需要进行判断
if (typeof then === 'function') {
// 在return的回调中,可能还存在一个thenable对象,需要进行递归处理
then.call(
x,
(res) => resolvePromise(promise2, res, resolve, reject),
(err) => reject(err)
)
} else {
// then不是函数时,直接抛出返回值
resolve(x)
}
} catch (error) {
// return的回调报错时,抛出错误
reject(error)
}
} else {
// return 非thenable对象
// .then不管是成功的回调还是失败的回调,return的结果一定在下一次.then的成功回调接收
resolve(x)
}
}
标签:resolve,const,res,Promise,promise,reject,原理,手写
From: https://www.cnblogs.com/yaofanrenshi/p/17230659.html