Promise
规范
目前,Promise 有两种规范:
静态属性
Promise[@@species]
静态访问器属性 Promise[@@species] 返回用于构造 Promise 方法返回值的构造函数。
静态方法
Promise.all()
- 接收一个 promise 可迭代对象作为输入,并返回一个单独的 promise
- 返回的 promise 在所有输入的 promise 都成功兑现时(包括传入的可迭代对象为空时),返回值为一个包含所有成功兑现值的数组
如果输入的任何一个 promise 被拒绝,则返回的 promise 也将被拒绝,并返回第一个被拒绝的原因(在创建实例时,Promise.all 内部的实例就已经执行了)
js
Promise.all = function(list) {
return new Promise((resolve, reject) => {
let count = 0 // 计数器
let result = [] // 存放结果
let len = list.length
if (!len)
resolve([])
for (const item of list) {
Promise.resolve(item)
.then(val => {
count++
result[i] = val // 收集每个 promise 的返回值
// 所有 promise 都成功后,将返回结果
if (count === len)
resolve(result)
})
.catch(err => reject(err))
}
})
}
Promise.allSettled()
- 接收一个 promise 可迭代对象作为输入,并返回一个单独的 Promise
- 返回的 promise 在输入的 promise 都确定时(包括传入的可迭代对象为空时),返回的 promise 将被兑现,返回值为一个描述每个 promise 结果的对象数组
只有等到参数数组的所有 promise 对象都发生状态变更(无论是 fulfilled / rejected),返回的 promise 对象才会发生状态变更,一旦发生状态变更,状态总是 fulfilled,不会变为 rejected
js
Promise.allSettled = function(list) {
return new Promise((resolve, reject) => {
let count = 0 // 计数器
let result = [] // 存放结果
let len = list.length
if (!len)
return []
for (let item of list) {
// 有的数据项可能不是 promise,因此需要包装一下
Promise.resolve(item)
.then(val => {
count++
// 成功属性设置
result[i] = {
status: "fulfilled",
value: val
}
// 当所有的 promise 都成功后,返回结果
if (count === len) {
resolve(result)
}
})
.catch(err => {
count++
// 失败属性设置
result[i] = {
status: "rejected",
reason: err
}
// 当所有的 promise 都失败后,返回结果
if (count === len) {
reject(result)
}
})
}
})
}
Promise.any()
- 接受一个 promise 可迭代对象作为输入,并返回单个 promise
- 返回的 promise 在任何输入的 promise 兑现时兑现,其值为第一个兑现的值
- 如果输入的 promise 都被拒绝(包括传入的可迭代对象为空时),返回的 promise 将以带有一个包含拒绝原因的数组 AggregateError 拒绝
只有全部实例都失败后才会返回失败,如果有一个实例的状态返回成功,则返回第一个成功的实例
js
// 手动实现 Promise.any
Promise.any = function(list) {
return new Promise((resolve, reject) => {
let count = 0 // 计数器
let len = list.length
if (!len) return
for (let item of list) {
// 有的数据项可能不是 promise,因此需要包装一下
Promise.resolve(item)
.then(res => resolve(res))
.catch(err => {
count++
// 当所有的 promise 都失败后,返回结果
if (count === len) {
return reject(new Error("All promises where rejected"))
}
})
}
})
}
Promise.race()
- 接受一个 promise 可迭代对象作为输入,并返回单个 promise
- 返回的 promise 与第一个敲定的 promise 的最中状态保持一致
传入的所有实例哪一个实例的状态率先改变,那么就会返回哪个实例的返回值,无论成功还是失败
js
Promise.race = function(list) {
return new Promise((resolve, reject) => {
for (let item of list) {
// 有的数据项可能不是 promise,因此需要包装一下
// 另一个原因是:避免非 promise 对象同时进行状态监听
Promise.resolve(item)
.then(res => resolve(res))
.catch(err => reject(err))
}
})
}
Promise.resolve()
- 返回一个新的 promise 对象,该对象以给定的值兑现
- 如果值是一个 thenable 对象(即具有 then 方法),则返回的 promise 对象会跟随该 thenable 对象,采用其最终的状态。否则,返回的 promise 对象会以该值兑现
- 通常,如果不清楚一个值是否是 promise,最好使用 promise.resolve 将其转换为 promise 对象,并将返回值作为 promsie 来处理
js
function isPromiseLike(obj) {
return obj && typeof 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 => resolve(value))
}
Promise.reject()
- 返回一个新的 promise 对象,该对象以给定的原因拒绝
js
Promise.reject = function(reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
}
Promise.withResolvers()
- 返回一个对象,其包含一个新的 Promise 对象和两个函数,用于解决或拒绝它,对应于传入给 Promise() 构造函数执行器的两个参数
Promise.withResolvers() 完全等同于以下代码:
js
let resolve, reject
const promise = new Promise((res, rej) => {
resolve = res
reject = rej
})
实例方法
Promise.prototype.then()
- 将一个拒绝处理回调函数附加到 promise 上,并返回一个新的 promise,如果回调被调用,则解决为回调的返回值,如果 promise 被兑现,解决为其原始兑现值
Promise.prototype.catch()
- 将一个处理去附加到 promise 上,并返回一个新的 promise,当原始 promise 被解决时解决。无论 promise 是否被兑现或者被拒绝,处理器都会在 promise 敲定时被调用
Promise A+ 规范中未定义,ES Promise 中仅仅是 Promise.prototype.then(undefined, onRejected) 的语法糖
js
Promise.prototype.catch = function(onRejected) {
return this.then(undefined, onRejected)
}
Promise.prototype.finally()
- 将一个兑现处理器和拒绝处理器附加到 promise 上,并返回一个新的 promise,解决为调用处理器得到的返回值,或者如果 promise 没有被处理(即相关处理器 onFulfilled 或 onRejected 不是函数),则以原始敲定值解决
PromiseLike
js
function isPromiseLike(obj) {
return obj && typeof obj.then === 'function'
}
A+ 规范实现
js
// 定义三个状态
const PENDING = "PENDING"
const FULFILLED = "FULFILLED"
const REJECTED = "REJECTED"
// promise 是一个构造函数
class _Promise {
// executor 代表执行器函数
constructor(executor) {
// 初始化状态
this.status = PENDING
// 初始化返回值
this.value = undefined
this.reason = undefined
// resolved 和 rejected 回调函数池
this.onResolvedCallbackList = []
this.onRejectedCallbackList = []
// resolve 和 reject 回调函数
// 需要做异常捕获
const resolve = value => {
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
this.onResolvedCallbackList.forEach(fn => fn())
}
}
const reject = reason => {
if (this.status === PENDING) {
this.status = FULFILLED
this.reason = reason
this.onRejectedCallbackList.forEach(fn => fn())
}
}
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
// 核心方法
resolvePromise(promise, next, resolve, reject) {
if (next === promise) {
// 死循环
return reject(new TypeError("message"))
}
// 是否被调用
let called
if (
(typeof next === "object" && next !== null) ||
typeof next === "function"
) {
try {
// 判断参数类型
if (typeof next.then === "function") {
const resolveArg = resolveNext => {
this.resolvePromise(promise, resolveNext, resolve, reject)
}
const rejectArg = rejectNext => {
if (called) return
called = true
this.resolvePromise(promise, rejectNext, resolve, reject)
}
// 函数执行, 补充参数
next.then.call(next, resolveArg, rejectArg)
} else {
resolve(next)
}
} catch (err) {
if (called) return
called = true
reject(err)
}
} else {
reject(next)
}
}
// 实例方法
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (function (val) {
return val
})
onRejected = typeof onRejected === "function" ? onRejected : (function (val) {
return val
})
const promise = new _Promise((resolve, reject) => {
const resolveCallback = () => {
try {
const next = onFulfilled(this.value)
this.resolvePromise(promise, next, resolve, reject)
} catch (err) {
reject(err)
}
}
const rejectCallback = () => {
try {
const next = onRejected(this.reason)
this.resolvePromise(promise, next, resolve, reject)
} catch (err) {
reject(err)
}
}
if (this.status === FULFILLED) {
// 模拟异步
setTimeout(resolveCallback)
}
if (this.status === REJECTED) {
// 模拟异步
setTimeout(rejectCallback)
}
if (this.status === PENDING) {
// 加入池子
this.onResolvedCallbackList.push(resolveCallback)
this.onRejectedCallbackList.push(rejectCallback)
}
})
return promise
}
catch(callback) {
this.then(undefined, callback)
}
// 静态方法
static all(promiseList) {
return new _Promise((resolve, reject) => {
let count = 0
let result = []
let len = promiseList.length
if (!len) {
resolve([])
}
for (let item of promiseList) {
_Promise.resolve(item)
.then(res => {
count += 1
result[i] = res
if (count === len) {
resolve(result)
}
})
.catch(err => {
reject(err)
})
}
})
}
static allSettled(promiseList) {
return new _Promise((resolve, reject) => {
let count = 0
let result = []
let len = promiseList.length
if (!len) {
return []
}
for (let item of promiseList) {
_Promise.resolve(item)
.then(res => {
count += 1
result[i] = {
status: "fulfilled",
value: res
}
if (count === len) {
resolve(result)
}
})
.catch(err => {
count += 1
result[i] = {
status: "rejected",
reason: err
}
if (count === len) {
reject(result)
}
})
}
})
}
static race(promiseList) {
return new _Promise((resolve, reject) => {
let count = 0
let result = []
let len = promiseList.length
if (!len) {
return []
}
for (let item of promiseList) {
_Promise.resolve(item)
.then(res => {
count += 1
result[i] = {
status: "fulfilled",
value: res
}
if (count === len) {
resolve(result)
}
})
.catch(err => {
count += 1
result[i] = {
status: "rejected",
reason: err
}
if (count === len) {
reject(result)
}
})
}
})
}
static any(promiseList) {
return new _Promise((resolve, reject) => {
let count = 0
let len = promiseList.length
if (!len) {
return
}
for (let item of promiseList) {
_Promise.resolve(item)
.then(res => resolve(res))
.catch(err => {
count += 1
if (count === len) {
return reject(new Error("All promises where rejected"))
}
})
}
})
}
}