携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情
Promise是什么
Promise是ES6推出的一个内置JS类,用于异步编程,相较于回调函数的方式,使用起来更优雅、更合理。
Promise中文释义是承诺的意思,Promise有三种状态:pending(进行中)、fulfilled(成功,即被resole了)、rejected(失败,即被reject或报错了),它的状态改变是单向的、不可逆的。
Promise的用法
基本用法
// 被resolve的情况
const promise1 = new Promise((resolve, reject) => {
resolve('resolved')
})
promise1.then(res => {
console.log(res) // 输出:resolved,对应上面resolve出来的值
})
// 被reject的情况
const promise2 = new Promise((resolve, reject) => {
reject('rejected')
})
// 第一种捕获错误的方式:promise.catch
promise2.then(res => {
console.log(res) // 不会触发
}).catch(err => {
console.log(err) // 输出:rejected
})
// 第二种捕获错误的方式:then的第二个回调函数
promise2.then(res => {
console.log(res) // 不会触发
}, err => {
console.log(err) // 输出:rejected
})
// finally,最终的意思,就是不管是fulfilled还是rejected,都会触发,但无法接收到值
promise1.finally((res) => {
console.log('finally') // promise1是fulfilled状态,会触发
console.log(res) // 输出undefined
})
promise2.finally((err) => {
console.log('finally') // promise2是rejected状态,也会触发
console.log(err) // 输出undefined
})
then、catch回调函数的返回值
then返回值
const promise = Promise.resolve(1)
promise.then(res => {
console.log(res) // 输出:1
return 2
}).then(res => {
console.log(res) // 输出:2,就是上一个回调函数的返回值
}).then(res => {
console.log(res) // 输出:undefined,上一个回调函数没有返回值,所以是undefined
})
promise.then(res => {
// 上面那个回调函数的返回值不会影响这个,只会影响后续的回调函数
// 原因是因为then每次都是返回一个新的Promise对象
console.log(res) // 输出:1
})
catch返回值
const promise = Promise.reject(1)
promise.catch(err => {
console.log(err) // 输出:1
return 2
}).catch(err => {
console.log(err) // 不触发,因为被catch后,后续就不会走catch了,而是then
}).then(res => {
console.log(res) // 输出:2
})
返回Promise对象
回调函数中如果返回的是Promise对象,后续的回调函数会等待Promise完成才会触发,且接收到的值也是返回的Promise的值,而不是这个Promise对象。
const promise = Promise.resolve(1)
promise.then(res => {
console.log(res) // 输出: 1
return new Promise(resolve => {
setTimeout(() => {
resolve(2)
}, 1000)
})
}).then(res => {
console.log(res) // 1s后输出:2,而不是一个Promise对象
})
回调函数返回的多层Promise都会被拉平
const promise = Promise.resolve(1)
promise.then(res => {
console.log(res) // 输出: 1
return new Promise(resolve => {
setTimeout(() => {
const promise3 = new Promise(resolve => {
setTimeout(() => {
resolve(2)
}, 1000)
})
resolve(promise3)
}, 1000)
})
}).then(res => {
console.log(res) // 2s后输出:2,会等待2层Promise都完成
})
如果非要返回一个Promise对象呢?返回的promise转换为别的数据结构
const promise = Promise.resolve(1)
promise.then(res => {
console.log(res) // 输出: 1
return {
promise: Promise.resolve(666)
}
}).then(res => {
console.log(res) // 输出:{ promise: Promise }
})
触发catch的方式
触发catch方式有三种:
- 第一种就是reject触发;
- 第二种就是Promise构造函数中报错;
- 第三种则是回调函数返回了一个rejected的Promise对象或者报错
// 1
const promise1 = new Promise((resolve, reject) => {
reject('rejected')
})
promise1.catch(err => {
console.log(err) // 输出:rejected
})
// 2
const promise2 = new Promise((resolve, reject) => {
throw 'throw rejected'
})
promise2.catch(err => {
console.log(err) // 输出:throw rejected,报错同样会被catch
})
// 3.1
const promise3 = new Promise((resolve, reject) => {
resolve('resolved')
})
promise3.then(res => {
console.log(res) // 输出:resolved
// 通过Promise的静态方法:reject,返回一个被reject的Promise对象
return Promise.reject('then rejected')
}).catch(err => {
console.log(err) // 输出:then rejected
})
// 3.2
const promise4 = new Promise((resolve, reject) => {
resolve('resolved')
})
promise4.then(res => {
console.log(res) // 输出:resolved
throw 'throw rejected' // 报错,会触发后面的catch
}).catch(err => {
console.log(err) // 输出:throw rejected
})
两种捕获错误的区别
其实通过上文的示例,不知道的小伙伴,这会大概已经猜到了,如果通过then的第一个回调函数触发的reject,不会被then的第二个回调函数接收。
const promise1 = new Promise((resolve, reject) => {
resolve('resolved')
})
promise1.then(res => {
console.log(res) // 输出:resolved
// 通过Promise的静态方法:reject,返回一个被reject的Promise对象
return Promise.reject('then rejected')
}, err => {
console.log(err) // 不会触发
}).catch(err => {
console.log(err) // 输出:then rejected
})
const promise2 = new Promise((resolve, reject) => {
resolve('resolved')
})
promise2.then(res => {
console.log(res) // 输出:resolved
throw 'throw rejected' // 报错,会触发后面的catch
}, err => {
console.log(err) // 还是不会触发
}).catch(err => {
console.log(err) // 输出:throw rejected
})
Promise的一些常用API
Promise.resolve
返回一个fulfilled的Promise对象
const promise = Promise.resovle('fulfilled')
promise.then(res => {
console.log(res) // 输出:fulfilled
})
Promise.reject
返回一个rejected的Promise对象
const promise = Promise.reject('rejected')
promise.catch(err => {
console.log(err) // 输出:rejected
})
Promise.all
接收一个Promise对象数组,生成一个新的Promise对象,只要有一个Promise对象rejected了,那么这个新的Promise的对象状态就变成了rejected;如果所有的都fulfilled了,那么这个新的Promise的对象状态就变成了fulfilled,then回调中可以接收到所有Promise返回值组成的数组。
const promise1 = Promise.resolve(1)
const promise2 = Promise.resolve(2)
const promise3 = Promise.reject(3)
Promise.all([
promise1,
promise2,
promise3,
]).then(res => {
console.log(res) // 不触发
}).catch(err => {
console.log(err) // 输出:3
})
Promise.all([
promise1,
promise2,
]).then(res => {
console.log(res) // 输入:[1, 2]
}).catch(err => {
console.log(err) // 不触发
})
Promise.allSettled
和Promise.all有点类似,是之后补充的一个新API;和all不同的是,它只会再所有Promise处理完成后(状态变成fullfilled或rejected)才会触发;只会触发then的第一个回调,接收到所有Promise的状态和值组成的数组。
const promise1 = Promise.resolve(1)
const promise2 = Promise.resolve(2)
const promise3 = Promise.reject(3)
Promise.allSettled([
promise1,
promise2,
promise3,
]).then(res => {
/**
* 输出:
* [
* { status: 'fulfilled', value: 1 },
* { status: 'fulfilled', value: 2 },
* { status: 'rejected', reason: 3 },
* ]
*/
console.log(res)
}).catch(err => {
console.log(err)
})
Promise.race
接收一个Promise对象数组,返回一个新的Promise对象,如果有一个Promise对象的状态率先改变,那么这个新的Promise对象的状态和值就是这个率先改变的Promise对象的状态和值。
const promise1 = new Promise((resolve) => {
setTimeout(() => {
resolve(1)
}, 100)
})
const promise2 = new Promise((resolve) => {
setTimeout(() => {
resolve(2)
}, 200)
})
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(3)
}, 50)
})
Promise.race([
promise1,
promise2,
]).then(res => {
console.log(res) // 输出:1
}).catch(err => {
console.log(err) // 不触发
})
Promise.race([
promise1,
promise2,
promise3,
]).then(res => {
console.log(res) // 不触发
}).catch(err => {
console.log(err) // 输出:3
})
Promise.any
接收一个Promise对象数组,返回一个新的Promise对象,当有一个Promise对象变成fullfiled状态,那么新的Promise对象就变成fullfiled状态,如果所有Promise对象变成rejected状态,新的Promise对象才变成rejected状态。
const promise1 = new Promise((resolve) => {
setTimeout(() => {
resolve(1)
}, 100)
})
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(2)
}, 200)
})
const promise3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(3)
}, 50)
})
Promise.any([
promise1,
promise2,
]).then(res => {
console.log(res) // 输出:1
}).catch(err => {
console.log(err) // 不触发
})
Promise.any([
promise2,
promise3,
]).then(res => {
console.log(res) // 不触发
}).catch(err => {
// 这里接收到err是AggregateError实例
// 输出:AggregateError: All promises were rejected
console.log(err)
})
全局捕获Promise的reject
在我们需要做错误监控时,通常都需要对未捕获的Promise做处理
window.addEventListener('unhandledrejection', (event) => {
const { promise, reason } = event
console.log(promise) // 未捕获的Promise对象
console.log(reason) // 原因,就是reject抛出来的内容
// 上报错误
reportError({
reason,
timestamp: Date.now()
})
// 阻止默认行为,可避免继续报错
event.preventDefault()
})
事件循环,宏任务和微任务
后续讲到的await和微任务有关,微任务又是事件循环的一部分,所以这里就先讲一下事件循环吧;这里讲的是浏览器的事件循环,Node的事件循环复杂很多,我就不讲啦(其实我也没搞明白)。
首先JS是单线程的,意味着所有的JS代码只会依次执行,遇到一些耗时的任务时,JS不能像其他多线程语言一样,可以另外开一个线程去执行,但JS也不能傻等吧,所以为了避免阻塞执行,就引入了事件循环机制,注意事件循环并不是JS的专属。
事件循环的机制大概是这样的,首先JS执行同步任务,当遇到异步任务,则会暂时将它添加到任务队列中,等到异步任务准备好了,会执行对应的回调,但需要等JS执行完本轮同步任务才会回过来头来处理这些回调,完成后,再执行下一轮,如此往复便是事件循环机制。
事件循环中的任务队列又分为宏任务和微任务;宏任务队列有多个,微任务队列只有一个;微任务是在宏任务中添加的;首先整个script标签创建了第一个宏任务队列,当遇到异步任务,如果是宏任务则会创建新的宏任务队列,如果是微任务,则会添加到微任务队列;如果新的宏任务队列中又有新的异步任务,那么就会像套娃一样,继续创建宏任务队列,添加微任务等等。
宏任务大概有这些:
- script整体代码
- setTimout
- setInterval
- setImmediate(node)
- requestAnimationFrame
微任务大概有这些:
- process.nextTick(node)
- Promise
- Object.observe
- MutationObserver
一道恶心的题
我这里就不贴答案了,大家自行思考,答案和分析放在文章末尾。
setTimeout(() => {
console.log(1)
})
console.log(2)
const promise = new Promise(resolve => {
resolve(3)
console.log(4)
})
promise.then(res => {
console.log(res)
})
function fn() {
console.log(5)
}
async function asyncFn() {
await fn()
console.log(6)
await promise
console.log(7)
}
console.log(8)
asyncFn().then(() => {
console.log(9)
})
console.log(10)
搭配async和await
async和await是异步编程的终极解决方案,使得写异步代码就像写同步代码一样丝滑。
基本使用
const promise1 = new Promise(resolve => {
setTimeout(() => {
resolve('resolved 1')
}, 1000)
})
const promise2 = new Promise(resolve => {
setTimeout(() => {
resolve('resolved 2')
}, 1000)
})
async function exec() {
console.log('start')
await promise1 // 等待promise1完成
console.log('promise1 fulfilled') // 1s后输出
const ret = promise2 // 等待promise2完成,接收了其resolve的值
console.log('promise2 fulfilled') // 2s后输出
console.log(`promise2 value: ${ret}`) // 输出resolve的值
}
exec()
捕获错误
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('rejected')
}, 1000)
})
async function exec1() {
console.log('start')
await promise1 // 等待promise1完成
console.log('promise1 fulfilled') // 不会输出
}
exec1() // 抛出错误,Uncaught (in promise) rejected
async function exec2() {
try {
console.log('start')
await promise1 // 等待promise1完成
console.log('promise1 fulfilled') // 不会输出
} catch(err) {
console.log(err) // 捕获到reject,err即reject的内容: rejected
}
}
exec2() // 不会抛出错误
await-to-js
可以看到使用await后,对错误处理还是挺麻烦的,这里推荐一个库:await-to-js,用法如下:
import to from 'await-to-js';
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
reject('rejected')
}, 1000)
})
async function exec() {
const [err, res] = await to(promise)
console.log(err) // 输出rejected
console.log(res) // 输出undefined
}
exec()
内部源码也非常简单:
function to (
promise,
errorExt
) {
return promise
.then((data) => [null, data])
.catch((err) => {
if (errorExt) {
const parsedError = Object.assign({}, err, errorExt)
return [parsedError, undefined]
}
return [err, undefined]
})
}
实例场景
接口超时
const handleTimeout = (promise, timeout) => {
return Promise.race([
promise,
new Promise((resolve, reject) => {
setTimeout(() => {
reject('请求超时')
}, timeout)
})
])
}
// 一分钟超时处理
handleTimeout(
ajax({
url: 'xxx'
}),
60 * 1000
)
响应拦截
为了描述我要要演示什么,先给大家看一下axios的响应拦截器用法吧
axios.interceptors.response.use(function (response) {
return response.data
})
相信大家都做过这样的操作吧,拦截响应,将响应值外面的data层去掉,那么这里面是如何实现的。
来吧,展示:
// 模拟一个获取用户列表的接口
const getUserList = () => {
return Promise.resolve({
data: [
{ name: 'ly', age: 18, id: 1 },
{ name: 'yl', age: 19, id: 2 },
]
})
}
const responseInterceptor = (_promise) => {
let promise = _promise
const ret = {
promise,
addInterceptor(resolve, reject) {
ret.promise = promise.then(resolve, reject)
}
}
return ret
}
const requestInstance = responseInterceptor(getUserList())
// 拦截,去除data外面的那一层
requestInstance.addInterceptor(res => {
return res.data
})
requestInstance.promise.then(res => {
/*
输出:
[
{ name: 'ly', age: 18, id: 1 },
{ name: 'yl', age: 19, id: 2 },
]
*/
console.log(res)
})
requestInstance.addInterceptor(res => {
return '你是大傻逼'
})
requestInstance.promise.then(res => {
// 输出:'你是大傻逼'
console.log(res)
})
拦截器还有很多其他用处,如:将code非200的情况转为rejected的Promise对象,以方便使用。
串行请求
- 方法1(await)
const getUserList = () => {
return new Promise(resolve => {
setTimeout(() => {
resolve([
{ name: 'ly', age: 18, id: 1 },
{ name: 'yl', age: 19, id: 2 },
])
}, 500)
}).then(res => {
console.log(res)
})
}
const getOrgList = () => {
return new Promise(resolve => {
setTimeout(() => {
resolve([
{ orgName: '友谊的小船', id: 1 },
{ orgName: '五黑小分队', id: 2 },
])
}, 500)
}).then(res => {
console.log(res)
})
}
const tasks = [getUserList, getOrgList]
async function exec() {
for(const task of tasks) {
await task()
}
console.log('all task completed')
}
exec()
- 方法2(反复赋值promise)
const getUserList = () => {
return new Promise(resolve => {
setTimeout(() => {
resolve([
{ name: 'ly', age: 18, id: 1 },
{ name: 'yl', age: 19, id: 2 },
])
}, 500)
}).then(res => {
console.log(res)
})
}
const getOrgList = () => {
return new Promise(resolve => {
setTimeout(() => {
resolve([
{ orgName: '友谊的小船', id: 1 },
{ orgName: '五黑小分队', id: 2 },
])
}, 500)
}).then(res => {
console.log(res)
})
}
const tasks = [getUserList, getOrgList]
let promise = tasks.shift()()
tasks.forEach(task => {
promise = promise.then(() => task())
})
promise.then(() => {
console.log('all task completed')
})
并行请求
讲了串行,并行不是简简单单吗,就是Promise.all和Promise.allSettled的应用,这里就不重复讲了,上文已提到。
源码实现
- 首先定义三个状态,写出构造函数
class MyPromise {
static PENDING = 'pending'
static FULFILLED = 'fulfilled'
static REJECTED = 'rejected'
constructor(exec) {
this.state = MyPromise.PENDING // 初始为pending状态
this.result = null // promise的结果
// 同步执行exec,传递两个回调函数,注意绑定this(不明白的小朋友们去补习下js基础哦)
exec(this.resolve.bind(this), this.reject.bind(this))
}
}
- 初步实现resolve和reject
class MyPromise {
resolve(result) {
// 添加判断,保证状态不可变,Promise可是一个有原则的类
if (this.state === MyPromise.PENDING) {
this.result = result;
this.state = MyPromise.FULFILLED;
}
}
reject(result) {
// 同上,保证状态不可变
if (this.state === MyPromise.PENDING) {
this.result = result;
this.state = MyPromise.REJECTED;
}
}
}
- 重头戏!实现then,完善resolve、reject
class MyPromise {
constructor() {
...
// 增加两个回调函数存储器
this.fulfilledCallbacks = [];
this.rejectedCallbacks = [];
}
resolve(result) {
if (this.state === MyPromise.PENDING) {
// 因为promise.then是异步的,所以用setTimeout模拟一下,但注意并不是微任务
setTimeout(() => {
this.result = result;
this.state = MyPromise.FULFILLED;
// 执行所有的fulfilledCallback
this.fulfilledCallbacks.forEach(callback => callback(this.result));
})
}
}
reject(result) {
if (this.state === MyPromise.PENDING) {
setTimeout(() => {
this.result = result;
this.state = MyPromise.REJECTED;
// 执行所有的rejectedCallback
this.rejectedCallbacks.forEach(callback => callback(this.result));
})
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof (onFulfilled) === 'function' ? onFulfilled : value => value;
onRejected = typeof (onRejected) === 'function' ? onRejected : reason => { throw reason };
if (this.state === MyPromise.FULFILLED) {
// 如果此时已经为fulfilled,则立即执行onFulfilled回调
setTimeout(() => {
onFulfilled(this.result);
})
} else if (this.state === MyPromise.REJECTED) {
// 如果此时已经为rejected,则立即执行onRejected回调
setTimeout(() => {
onRejected(this.result)
})
} else if (this.state === MyPromise.PENDING) {
// pending中,则暂存到数组中
this.fulfilledCallbacks.push(() => {
onFulfilled(this.result)
})
this.rejectedCallbacks.push(() => {
onRejected(this.result)
})
}
}
}
到这里一个非常简陋的Promise就实现了,但还缺少了很多功能,后面继续完善,加油。
- 完善then,实现链式调用、值传递
class MyPromise {
then(onFulfilled, onRejected) {
onFulfilled = typeof (onFulfilled) === 'function' ? onFulfilled : value => value;
onRejected = typeof (onRejected) === 'function' ? onRejected : reason => { throw reason };
const promise = new MyPromise((resolve, reject) => {
// 如果此时已经为fulfilled,则立即执行success回调
if (this.state === MyPromise.FULFILLED) {
setTimeout(() => {
try {
const res = onFulfilled(this.result);
resolve(res);
} catch (err) {
reject(err);
}
})
} else if (this.state === MyPromise.REJECTED) {
// 如果此时已经为rejected,则立即执行fail回调
setTimeout(() => {
try {
const res = onRejected(this.result);
reject(res);
} catch (err) {
reject(err);
}
})
} else if (this.state === MyPromise.PENDING) {
this.fulfilledCallbacks.push(() => {
try {
const res = onFulfilled(this.result);
resolve(res);
} catch (err) {
reject(err);
}
});
this.rejectedCallbacks.push(() => {
try {
const res = onRejected(this.result);
reject(res);
} catch (err) {
reject(err);
}
});
}
})
return promise;
}
}
- 继续完善then,解析回调函数返回的Promise
class MyPromise {
then(onFulfilled, onRejected) {
onFulfilled = typeof (onFulfilled) === 'function' ? onFulfilled : value => value;
onRejected = typeof (onRejected) === 'function' ? onRejected : reason => { throw reason };
const promise = new MyPromise((resolve, reject) => {
// 如果此时已经为fulfilled,则立即执行success回调
if (this.state === MyPromise.FULFILLED) {
setTimeout(() => {
try {
const res = onFulfilled(this.result);
MyPromise.resolvePromise(promise, res, resolve, reject);
return;
if (res instanceof MyPromise) {
res.then(resolve, reject);
} else {
resolve(res);
}
} catch (err) {
reject(err);
}
})
} else if (this.state === MyPromise.REJECTED) {
// 如果此时已经为rejected,则立即执行fail回调
setTimeout(() => {
try {
const res = onRejected(this.result);
MyPromise.resolvePromise(promise, res, resolve, reject);
return;
if (res instanceof MyPromise) {
res.then(resolve, reject);
} else {
reject(res);
}
} catch (err) {
reject(err);
}
})
} else if (this.state === MyPromise.PENDING) {
this.fulfilledCallbacks.push(() => {
try {
const res = onFulfilled(this.result);
MyPromise.resolvePromise(promise, res, resolve, reject);
return;
if (res instanceof MyPromise) {
res.then(resolve, reject);
} else {
resolve(res);
}
} catch (err) {
reject(err);
}
});
this.rejectedCallbacks.push(() => {
try {
const res = onRejected(this.result);
MyPromise.resolvePromise(promise, res, resolve, reject);
return;
if (res instanceof MyPromise) {
res.then(resolve, reject);
} else {
reject(res);
}
} catch (err) {
reject(err);
}
});
}
})
return promise;
}
static resolvePromise(promise, retVal, resolve, reject) {
if (retVal instanceof MyPromise) {
if (retVal.state === MyPromise.PENDING) {
retVal.then(res => {
// 递归,不管resolve中套了多少层的promise都给解析出来
MyPromise.resolvePromise(promise, res, resolve, reject)
}, reject);
} else if (retVal.state === MyPromise.FULFILLED) {
resolve(retVal.result);
} else if (retVal.state === MyPromise.REJECTED) {
reject(retVal.result);
}
} else {
return resolve(retVal);
}
}
}
收工,then函数已经完成,咱这个盗版基本上正版差不多了。
再完善亿点点细节,完整源码奉上:
- catch实际上就是调用了then;
- finally就是调用then,然后两个回调函数都调用finally的回调;
- 静态resolve、reject就是创建一个Promise对象,然后立马调用resolve或reject;
class MyPromise {
static PENDING = 'pending';
static FULFILLED = 'fulfilled';
static REJECTED = 'rejected';
constructor(exec) {
this.fulfilledCallbacks = [];
this.rejectedCallbacks = [];
this.state = MyPromise.PENDING;
this.result = null;
try {
exec(this.resolve.bind(this), this.reject.bind(this));
} catch (err) {
this.reject(err);
}
}
static resolve(result) {
return new MyPromise((resolve) => {
resolve(result);
})
}
static reject(result) {
return new MyPromise((resolve, reject) => {
reject(result);
})
}
resolve(result) {
// 保持state不可逆
if (this.state === MyPromise.PENDING) {
setTimeout(() => {
this.result = result;
this.state = MyPromise.FULFILLED;
// 执行所有的successCallback
this.fulfilledCallbacks.forEach(callback => callback(this.result));
})
}
}
reject(result) {
// 保持state不可逆
if (this.state === MyPromise.PENDING) {
setTimeout(() => {
this.result = result;
this.state = MyPromise.REJECTED;
// 执行所有的failCallback
this.rejectedCallbacks.forEach(callback => callback(this.result));
})
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof (onFulfilled) === 'function' ? onFulfilled : value => value;
onRejected = typeof (onRejected) === 'function' ? onRejected : reason => { throw reason };
const promise = new MyPromise((resolve, reject) => {
// 如果此时已经为fulfilled,则立即执行success回调
if (this.state === MyPromise.FULFILLED) {
setTimeout(() => {
try {
const res = onFulfilled(this.result);
MyPromise.resolvePromise(promise, res, resolve, reject);
return;
if (res instanceof MyPromise) {
res.then(resolve, reject);
} else {
resolve(res);
}
} catch (err) {
reject(err);
}
})
} else if (this.state === MyPromise.REJECTED) {
// 如果此时已经为rejected,则立即执行fail回调
setTimeout(() => {
try {
const res = onRejected(this.result);
MyPromise.resolvePromise(promise, res, resolve, reject);
return;
if (res instanceof MyPromise) {
res.then(resolve, reject);
} else {
reject(res);
}
} catch (err) {
reject(err);
}
})
} else if (this.state === MyPromise.PENDING) {
this.fulfilledCallbacks.push(() => {
try {
const res = onFulfilled(this.result);
MyPromise.resolvePromise(promise, res, resolve, reject);
return;
if (res instanceof MyPromise) {
res.then(resolve, reject);
} else {
resolve(res);
}
} catch (err) {
reject(err);
}
});
this.rejectedCallbacks.push(() => {
try {
const res = onRejected(this.result);
MyPromise.resolvePromise(promise, res, resolve, reject);
return;
if (res instanceof MyPromise) {
res.then(resolve, reject);
} else {
reject(res);
}
} catch (err) {
reject(err);
}
});
}
})
return promise;
}
catch(onRejected) {
return this.then(null, onRejected);
}
finally(callback) {
const P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason }),
)
}
static resolvePromise(promise, retVal, resolve, reject) {
if (retVal instanceof MyPromise) {
if (retVal.state === MyPromise.PENDING) {
retVal.then(res => {
// 递归,不管resolve中套了多少层的promise都给解析出来
MyPromise.resolvePromise(promise, res, resolve, reject)
}, reject);
} else if (retVal.state === MyPromise.FULFILLED) {
resolve(retVal.result);
} else if (retVal.state === MyPromise.REJECTED) {
reject(retVal.result);
}
} else {
return resolve(retVal);
}
}
}
最后再来点饭后甜点:实现all、allSettled、race
Promise.all
MyPromise.all = function (promises) {
return new Promise((resolve, reject) => {
const result = []
let fulfilledCount = 0
promises.forEach((promise, index) => {
promise.then(res => {
result[index] = res
fulfilledCount ++
if(fulfilledCount === promises.length) {
resolve(result)
}
}, err => {
reject(err)
})
})
})
}
Promise.allSettled
MyPromise.allSettled = function (promises) {
return new Promise((resolve, reject) => {
const result = []
let completedCount = 0
const callback = (value, index) => {
result[index] = value
completedCount ++
if(completedCount === promises.length) {
resolve(result)
}
}
promises.forEach((promise, index) => {
promise.then(res => {
callback({
status: 'fulfilled',
value: res
}, index)
}, err => {
callback({
status: 'rejected',
reson: err
}, index)
})
})
})
}
Promise.race
MyPromise.race = function (promises) {
return new Promise((resolve, reject) => {
promises.forEach((promise, index) => {
promise.then(resolve, reject)
})
})
}
事件循环题目解析
首先公布下答案:2 4 8 5 10 3 6 7 9 1
- 首先遇到
setTimeout,是一个宏任务,不管它,继续,输出一个2; - 继续,创建了一个
Promise对象,resolve(3)不管它,继续,输出了一个4,因为Promise构造函数接收的回调函数是被同步执行的,那么第二个输出的就是它了(4); - 继续,监听了
promise的回调,不管它; - 继续,声明了一个同步函数:
fn,不管它; - 继续,声明了一个异步函数:
asyncFn,不管它; - 继续,输出了8,那么第三个就是它了(8),没毛病吧,坚持住;
- 继续,执行了
asyncFn,并且监听了回调,asyncFn中写了句:await fn(),尽管左边有个await,但await右边仍然是会被同步执行的,所以第四个就是fn中输出的5; - 继续,注意,第五个可不是紧随其后的输出6,而是10,因为
await会形成一个微任务,所以会等之前的同步任务执行完成; - 继续,第六个输出的是3,而不是6,因为
promise的回调监听是在await fn()之前执行的; - 继续,输出6,没什么异议吧;
- 继续,输出7,再输出9,没异议吧;
- 继续,都执行完了,
setTimeout:是不是该想起我了?最后输出1。
完结🎉,感谢收看。