目录
手写promise
同步版
1.Promise的构造方法接收一个executor(),在new Promise()时就立刻执行executor回调
2.executor()内部的异步任务被放入宏/微任务队列,等待执行
3.状态与结果的管理
状态只能变更一次
4.then()调用成功/失败回调
catch是调用失败回调的简写
异步版
1.缓存成功与失败回调
2.then 增加 Pending处理
3.resolve 与 reject 中调用回调函数
多次调用同一个promise的then
1.缓存成功与失败回调 队列
2.pengding时,then()收集依赖,将成功/失败回调放入成功/失败队列
3.触发resolve/reject,从成功/失败队列中取出回调依次执行
then链式调用:返回一个 Promise 对象
then返回自己时,抛错循环调用
等返回的promise初始化好:queueMicrotask微任务
捕获错误
executor错误
then错误
then([onFulfilled, onRejected])参数可选
then 穿透:忽略非函数参数,非函数会同步执行
静态调用resolve、reject
完整版
Promise A+ 规范版的resolvePromise
catch
finally
并发请求
模板
all
allSettled
any
race
手写promise
同步版
1.将promise的resolve和reject函数传给实例用
constructor(executor){ // executor 是一个执行器,进入会立即执行 // 并传入resolve和reject方法 executor(this.resolve, this.reject) }
2.实例给resolve和reject函数传值
resolve('success') reject('err')
// 新建 test.js
// 引入我们的 MyPromise.js
const MyPromise = require('./MyPromise')
const promise = new MyPromise((resolve, reject) => {
resolve('success')
reject('err')
})
promise.then(value => {
console.log('resolve', value)
}, reason => {
console.log('reject', reason)
})
// 执行结果:resolve success
1.Promise
的构造方法接收一个executor()
,在new Promise()
时就立刻执行executor回调
class Promise{
// 构造方法接收一个回调
constructor(executor){
executor();
}
2.executor()
内部的异步任务被放入宏/微任务队列,等待执行
// resolve和reject为什么要用箭头函数?
// 如果直接调用的话,普通函数this指向的是window或者undefined
// 用箭头函数就可以让this指向当前实例对象
class MyPromise {
constructor(executor){
// executor 是一个执行器,进入会立即执行
// 并传入resolve和reject方法
executor(this.resolve, this.reject)
}
// 更改成功后的状态
resolve = () => {}
// 更改失败后的状态
reject = () => {}
}
3.状态与结果的管理
状态只能变更一次
// 先定义三个常量表示状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
// 新建 MyPromise 类
class MyPromise {
constructor(executor){
...
}
// 储存状态的变量,初始值是 pending
status = PENDING;
// 成功之后的值
value = null;
// 失败之后的原因
reason = null;
// 更改成功后的状态
resolve = (value) => {
// 只有状态是等待,才执行状态修改
if (this.status === PENDING) {
// 状态修改为成功
this.status = FULFILLED;
// 保存成功之后的值
this.value = value;
}
}
// 更改失败后的状态
reject = (reason) => {
// 只有状态是等待,才执行状态修改
if (this.status === PENDING) {
// 状态成功为失败
this.status = REJECTED;
// 保存失败后的原因
this.reason = reason;
}
}
}
4.then()调用
成功/失败回调
catch
是调用
失败回调的简写
// MyPromise.js
then(onFulfilled, onRejected) {
// 判断状态
if (this.status === FULFILLED) {
// 调用成功回调,并且把值返回
onFulfilled(this.value);
} else if (this.status === REJECTED) {
// 调用失败回调,并且把原因返回
onRejected(this.reason);
}
}
异步版
// test.js
const MyPromise = require('./MyPromise')
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 2000);
})
promise.then(value => {
console.log('resolve', value)
}, reason => {
console.log('reject', reason)
})
// 同步版没有打印信息(执行到then时,状态还是pending)
// 异步版等待 2s 输出 resolve success
1.缓存成功与失败回调
// MyPromise 类中新增
// 存储成功回调函数
onFulfilledCallback = null;
// 存储失败回调函数
onRejectedCallback = null;
2.then 增加 Pending处理
// MyPromise.js
then(onFulfilled, onRejected) {
...
if (this.status === PENDING) {
// ==== 新增 ====
// 因为不知道后面状态的变化情况,所以将成功回调和失败回调存储起来
// 等到执行成功失败函数的时候再传递
this.onFulfilledCallback = onFulfilled;
this.onRejectedCallback = onRejected;
}
}
3.resolve 与 reject 中调用回调函数
// MyPromise.js
// 更改成功后的状态
resolve = (value) => {
// 只有状态是等待,才执行状态修改
if (this.status === PENDING) {
// 状态修改为成功
this.status = FULFILLED;
// 保存成功之后的值
this.value = value;
// ==== 新增 ====
// 判断成功回调是否存在,如果存在就调用
this.onFulfilledCallback && this.onFulfilledCallback(value);
}
}
多次调用同一个promise的then
// test.js
const MyPromise = require('./MyPromise')
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 2000);
})
promise.then(value => {
console.log(1)
console.log('resolve', value)
})
promise.then(value => {
console.log(2)
console.log('resolve', value)
})
promise.then(value => {
console.log(3)
console.log('resolve', value)
})
//单个回调:
3
resolve success
//回调队列:
1
resolve success
2
resolve success
3
resolve success
1.缓存成功与失败回调 队列
// MyPromise.js
// 存储成功回调函数
// onFulfilledCallback = null;
onFulfilledCallbacks = [];
// 存储失败回调函数
// onRejectedCallback = null;
onRejectedCallbacks = [];
2.pengding时,then()收集依赖
,将成功/失败回调放入成功/失败队列
// MyPromise.js
then(onFulfilled, onRejected) {
// 判断状态
if (this.status === FULFILLED) {
// 调用成功回调,并且把值返回
onFulfilled(this.value);
} else if (this.status === REJECTED) {
// 调用失败回调,并且把原因返回
onRejected(this.reason);
} else if (this.status === PENDING) {
// ==== 新增 ====
// 因为不知道后面状态的变化,这里先将成功回调和失败回调存储起来
// 等待后续调用
this.onFulfilledCallbacks.push(onFulfilled);
this.onRejectedCallbacks.push(onRejected);
}
}
3.
触发resolve/reject
,从成功/失败队列中取出回调依次执行
// MyPromise.js
// 更改成功后的状态
resolve = (value) => {
// 只有状态是等待,才执行状态修改
if (this.status === PENDING) {
// 状态修改为成功
this.status = FULFILLED;
// 保存成功之后的值
this.value = value;
// ==== 新增 ====
// resolve里面将所有成功的回调拿出来执行
while (this.onFulfilledCallbacks.length) {
// Array.shift() 取出数组第一个元素,然后()调用,shift不是纯函数,取出后,数组将失去该元素,直到数组为空
this.onFulfilledCallbacks.shift()(value)
}
}
}
then链式调用:返回一个 Promise 对象
以fulfilled为例,其他同理
// MyPromise.js
class MyPromise {
...
then(onFulfilled, onRejected) {
// 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去
const promise2 = new MyPromise((resolve, reject) => {
// 这里的内容在执行器中,会立即执行
if (this.status === FULFILLED) {
// 获取成功回调函数的执行结果
const x = onFulfilled(this.value);
// 传入 resolvePromise 集中处理
resolvePromise(x, resolve, reject);
} ...
})
return promise2;
}
}
function resolvePromise(x, resolve, reject) {
// 判断x是不是 MyPromise 实例对象
if(x instanceof MyPromise) {
// 执行 x,调用 then 方法,目的是将其状态变为 fulfilled 或者 rejected
// x.then(value => resolve(value), reason => reject(reason))
// 简化之后
x.then(resolve, reject)
} else{
// 普通值
resolve(x)
}
}
then返回自己时,抛错循环调用
// test.js
const promise = new Promise((resolve, reject) => {
resolve(100)
})
const p1 = promise.then(value => {
console.log(value)
return p1
})
function resolvePromise(promise2, x, resolve, reject) {
// 如果相等了,说明return的是自己,抛出类型错误并返回
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
...
}
等返回的promise初始化好:queueMicrotask微任务
// MyPromise.js
class MyPromise {
......
then(onFulfilled, onRejected) {
const promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
// 创建一个微任务等待 promise2 完成初始化
queueMicrotask(() => {
// 获取成功回调函数的执行结果
const x = onFulfilled(this.value);
// 传入 resolvePromise 集中处理
resolvePromise(promise2, x, resolve, reject);
})
} ...
})
return promise2;
}
}
捕获错误
try {
异步操作
} catch (error) {
reject(error)
}
executor错误
// MyPromise.js
constructor(executor){
// ==== 新增 ====
// executor 是一个执行器,进入会立即执行
// 并传入resolve和reject方法
try {
executor(this.resolve, this.reject)
} catch (error) {
// 如果有错误,就直接执行 reject
this.reject(error)
}
}
then错误
// MyPromise.js
then(onFulfilled, onRejected) {
// 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去
const promise2 = new MyPromise((resolve, reject) => {
// 判断状态
if (this.status === FULFILLED) {
// 创建一个微任务等待 promise2 完成初始化
queueMicrotask(() => {
try {
// 获取成功回调函数的执行结果
const x = onFulfilled(this.value);
// 传入 resolvePromise 集中处理
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
})
} ...
})
return promise2;
}
then([onFulfilled, onRejected])参数可选
then 穿透:忽略非函数参数,非函数会同步执行
Promise.resolve(1)
.then(2)//传入值
.then(Promise.resolve(3))//传入promise对象
.then(console.log)//传入函数
1
Promise.resolve()
.then(new Promise(r => {
setTimeout(() => {
r(console.log(1))
}, 1000)
}))
.then(new Promise(r => {
setTimeout(() => {
r(console.log(2))
}, 1000)
}))
.then(new Promise(r => {
setTimeout(() => {
r(console.log(3))
}, 1000)
}))
延迟1秒后,打印123
不同于下面
// MyPromise.js
then(onFulfilled, onRejected) {
// 如果不传,就使用默认函数
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason};
// 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去
const promise2 = new MyPromise((resolve, reject) => {
......
}
静态调用resolve、reject
// MyPromise.js
MyPromise {
......
// resolve 静态方法
static resolve (parameter) {
// 如果传入 MyPromise 就直接返回
if (parameter instanceof MyPromise) {
return parameter;
}
// 转成常规方式
return new MyPromise(resolve => {
resolve(parameter);
});
}
// reject 静态方法
static reject (reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
});
}
}
完整版
// MyPromise.js
// 先定义三个常量表示状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
// 新建 MyPromise 类
class MyPromise {
constructor(executor){
// executor 是一个执行器,进入会立即执行
// 并传入resolve和reject方法
try {
executor(this.resolve, this.reject)
} catch (error) {
this.reject(error)
}
}
// 储存状态的变量,初始值是 pending
status = PENDING;
// 成功之后的值
value = null;
// 失败之后的原因
reason = null;
// 存储成功回调函数
onFulfilledCallbacks = [];
// 存储失败回调函数
onRejectedCallbacks = [];
// 更改成功后的状态
resolve = (value) => {
// 只有状态是等待,才执行状态修改
if (this.status === PENDING) {
// 状态修改为成功
this.status = FULFILLED;
// 保存成功之后的值
this.value = value;
// resolve里面将所有成功的回调拿出来执行
while (this.onFulfilledCallbacks.length) {
// Array.shift() 取出数组第一个元素,然后()调用,shift不是纯函数,取出后,数组将失去该元素,直到数组为空
this.onFulfilledCallbacks.shift()(value)
}
}
}
// 更改失败后的状态
reject = (reason) => {
// 只有状态是等待,才执行状态修改
if (this.status === PENDING) {
// 状态成功为失败
this.status = REJECTED;
// 保存失败后的原因
this.reason = reason;
// resolve里面将所有失败的回调拿出来执行
while (this.onRejectedCallbacks.length) {
this.onRejectedCallbacks.shift()(reason)
}
}
}
then(onFulfilled, onRejected) {
const realOnFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
const realOnRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason};
// 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去
const promise2 = new MyPromise((resolve, reject) => {
const fulfilledMicrotask = () => {
// 创建一个微任务等待 promise2 完成初始化
queueMicrotask(() => {
try {
// 获取成功回调函数的执行结果
const x = realOnFulfilled(this.value);
// 传入 resolvePromise 集中处理
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
})
}
const rejectedMicrotask = () => {
// 创建一个微任务等待 promise2 完成初始化
queueMicrotask(() => {
try {
// 调用失败回调,并且把原因返回
const x = realOnRejected(this.reason);
// 传入 resolvePromise 集中处理
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
})
}
// 判断状态
if (this.status === FULFILLED) {
fulfilledMicrotask()
} else if (this.status === REJECTED) {
rejectedMicrotask()
} else if (this.status === PENDING) {
// 等待
// 因为不知道后面状态的变化情况,所以将成功回调和失败回调存储起来
// 等到执行成功失败函数的时候再传递
this.onFulfilledCallbacks.push(fulfilledMicrotask);
this.onRejectedCallbacks.push(rejectedMicrotask);
}
})
return promise2;
}
// resolve 静态方法
static resolve (parameter) {
// 如果传入 MyPromise 就直接返回
if (parameter instanceof MyPromise) {
return parameter;
}
// 转成常规方式
return new MyPromise(resolve => {
resolve(parameter);
});
}
// reject 静态方法
static reject (reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
});
}
}
function resolvePromise(promise2, x, resolve, reject) {
// 如果相等了,说明return的是自己,抛出类型错误并返回
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
// 判断x是不是 MyPromise 实例对象
if(x instanceof MyPromise) {
// 执行 x,调用 then 方法,目的是将其状态变为 fulfilled 或者 rejected
// x.then(value => resolve(value), reason => reject(reason))
// 简化之后
x.then(resolve, reject)
} else{
// 普通值
resolve(x)
}
}
module.exports = MyPromise;
Promise A+ 规范版的resolvePromise
要求判断 x 是否为 object 或者 function,满足则接着判断 x.then 是否存在,这里可以理解为判断 x 是否为 promise,这里都功能实际与我们手写版本中 x instanceof MyPromise
功能相似
// MyPromise.js
function resolvePromise(promise, x, resolve, reject) {
// 如果相等了,说明return的是自己,抛出类型错误并返回
if (promise === x) {
return reject(new TypeError('The promise and the return value are the same'));
}
if (typeof x === 'object' || typeof x === 'function') {
// x 为 null 直接返回,走后面的逻辑会报错
if (x === null) {
return resolve(x);
}
let then;
try {
// 把 x.then 赋值给 then
then = x.then;
} catch (error) {
// 如果取 x.then 的值时抛出错误 error ,则以 error 为据因拒绝 promise
return reject(error);
}
// 如果 then 是函数
if (typeof then === 'function') {
let called = false;
try {
then.call(
x, // this 指向 x
// 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
y => {
// 如果 resolvePromise 和 rejectPromise 均被调用,
// 或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
// 实现这条需要前面加一个变量 called
if (called) return;
called = true;
resolvePromise(promise, y, resolve, reject);
},
// 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
r => {
if (called) return;
called = true;
reject(r);
});
} catch (error) {
// 如果调用 then 方法抛出了异常 error:
// 如果 resolvePromise 或 rejectPromise 已经被调用,直接返回
if (called) return;
// 否则以 error 为据因拒绝 promise
reject(error);
}
} else {
// 如果 then 不是函数,以 x 为参数执行 promise
resolve(x);
}
} else {
// 如果 x 不为对象或者函数,以 x 为参数执行 promise
resolve(x);
}
}
catch
//catch方法其实就是执行一下then的第二个回调
catch(rejectFn) {
return this.then(undefined, rejectFn)
}
finally
由于无法知道promise的最终状态,所以finally
的回调函数中不接收任何参数,它仅用于无论最终结果如何都要执行的情况
finally(callBack) {
return this.then(callBack, callBack)
}
并发请求
模板
/**
* @param {iterable} promises 一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入
* @returns
*/
static 并发(promises) {
// 参数校验
if (Array.isArray(promises)) {
let result = []; // 存储结果
let count = 0; // 计数器
if (promises.length === 0) {
// 如果传入的参数是一个空的可迭代对象,则返回一个已完成(already resolved)状态的 Promise
return resolve(promises);
//C. 返回一个 已失败(already rejected) 状态的 Promise。
return reject(new AggregateError('All promises were rejected'));
}
return new myPromise((resolve, reject) => {
promises.forEach((item, index) => {
myPromise.resolve(item).then(
value => {
count++;
// 每个promise执行的结果存储在result中
//A.记录所有reject/fulfilled,需要区分状态
result[index] = {
status: 'fulfilled',
value
}
//B.只记录fulfilled
result[index] = value
// 如果所有的 Promise 都已经处理完毕,就调用 resolve(result)
count === promises.length && resolve(result);
//C.只要一个成功
resolve(value);
},
reason => {
//A.记录所有reject
count++;
result[index] = {
status: 'rejected',
reason
}
count === promises.length && resolve(result);
//B.一旦reject
reject(reason);
//C.全reject
count++;
errors.push(reason);
//AggregateError是 Error 的一个子类,用于把单一的错误集合在一起。
count === promises.length && reject(new AggregateError(errors));
})
})
} else {
return reject(new TypeError('Argument is not iterable'))
}
}
all
/**
* 如果传入的 promise 中有一个失败(rejected),
* Promise.all 异步地将失败的那个结果给失败状态的回调函数,而不管其它 promise 是否完成
*/
static all(promises) {
return new myPromise((resolve, reject) => {
promises.forEach((item, index) => {
myPromise.resolve(item).then(
value => {
count++;
// 每个promise执行的结果存储在result中
result[index] = value;
// 如果所有的 Promise 都已经处理完毕,就调用 resolve(result)
count === promises.length && resolve(result);
},
reason => {
reject(reason);
})
})
}
allSettled
static allSettled(promises) {
return new myPromise((resolve, reject) => {
promises.forEach((item, index) => {
myPromise.resolve(item).then(
value => {
count++;
// 每个promise执行的结果存储在result中
//A.记录所有reject/fulfilled,需要区分状态
result[index] = {
status: 'fulfilled',
value
}
// 如果所有的 Promise 都已经处理完毕,就调用 resolve(result)
count === promises.length && resolve(result);
},
reason => {
//A.记录所有reject
count++;
result[index] = {
status: 'rejected',
reason
}
count === promises.length && resolve(result);
})
})
}
any
static any(promises){
return new myPromise((resolve, reject) => {
promises.forEach((item, index) => {
myPromise.resolve(item).then(
value => {
//C.只要一个成功
resolve(value);
},
reason => {
//C.全reject
count++;
errors.push(reason);
//AggregateError是 Error 的一个子类,用于把单一的错误集合在一起。
count === promises.length && reject(new AggregateError(errors));
})
})
}
race
//race方法(返回最早执行完的promise结果,无论成功与否)
Promise.race = function(promises){
return new myPromise((resolve, reject) => {
// 如果传入的迭代promises是空的,则返回的 promise 将永远等待。
if (promises.length > 0) {
promises.forEach(item => {
myPromise.resolve(item).then(resolve, reject);
})
}
}
})
手写实现 Promise 全部实例方法和静态方法,来看看 Promise.all、Promise.race 和 Promise.any 都是怎么实现的 - 掘金
从一道让我失眠的 Promise 面试题开始,深入分析 Promise 实现细节 - 掘金