Appearance
Promise 原理与实现
导航目录
什么是 Promise
- Promise 是 JavaScript 中用于处理异步操作的对象,它代表一个尚未完成但最终会完成的操作及其结果。Promise 提供了一种优雅的方式来处理异步操作,避免了回调地狱,使代码结构更加清晰和可维护。
- 通过 Promise,我们可以:
- 处理异步操作的成功和失败情况
- 实现链式调用,避免回调嵌套
- 更优雅地处理异步代码流程
Promise 优缺点
优点
- 解决回调地狱:通过链式调用替代多层嵌套回调,使代码结构更加清晰
- 错误处理统一:可以在链式调用的末尾集中处理错误
- 更好的代码组织:使异步操作的流程更加直观和可维护
- 支持并行操作:通过
Promise.all和Promise.race等方法实现多个异步操作的并行处理
缺点
- 无法取消:Promise 一旦创建,就无法中途取消或重置
- 错误处理需要注意:如果不添加错误处理,Promise 中的错误可能会被静默忽略
- 复杂性增加:对于简单的异步操作,使用 Promise 可能会增加代码的复杂性
Promise A+ 规范
- 所有的 Promise 都会遵循一个 Promise A+ 规范来实现Promise A+ 文档
1、Promise 执行器
- Promise 是一个类,当在实例化时,会立马执行构造器,构造器接受 resolve, reject 函数等待用户执行
WARNING
构造器在执行的时候如果出现异常直接会调用 reject 函数
js
class Promise {
constructor(executor) {
const resolve = (value) => {
console.log(value);
};
const reject = (reason) => {
console.log(reason);
};
try {
// 出现异常直接走reject
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
}
new Promise((resolve, reject) => {
resolve("ok");
});
new Promise((resolve, reject) => {
throw "error";
resolve("ok");
});2、Promise 状态
- Promise 有三种状态:
- pending(等待):初始状态,既不是成功也不是失败
- fulfilled(成功):操作成功完成
- rejected(失败):操作失败
- 状态转换规则:
- 状态只能从
pending转换为fulfilled或pending转换为rejected - 状态一旦转换,就不能再改变(不可逆)
- 状态只能从
- 状态与值的关系:
- 当状态变为
fulfilled时,会存储一个成功值 - 当状态变为
rejected时,会存储一个失败原因
- 当状态变为
js
const STATUS = {
PENDING: "PENDING",
FULFILLED: "FULFILLED",
REJECTED: "REJECTED",
};
class Promise {
constructor(executor) {
this.status = STATUS.PENDING;
this.value = undefined;
this.reason = undefined;
const resolve = (value) => {
if (this.status === STATUS.PENDING) {
this.status = STATUS.FULFILLED;
this.value = value;
}
};
const reject = (reason) => {
if (this.status === STATUS.PENDING) {
this.status = STATUS.REJECTED;
this.reason = reason;
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
}
new Promise((resolve, reject) => {
resolve("ok");
});
new Promise((resolve, reject) => {
reject("error");
});3、then 函数
- then 方法的参数:
- 接收两个回调函数:
onFulfilled(成功回调)和onRejected(失败回调)
- 接收两个回调函数:
- 参数处理:
- 如果传递的不是函数,会被转换为恒等函数(将值直接传递下去)
- 执行时机:
- 当 Promise 状态为
pending时,回调会被加入到队列中等待执行 - 当 Promise 状态为
fulfilled或rejected时,会直接调用对应的回调
- 当 Promise 状态为
- 返回值:
- then 方法返回一个新的 Promise,实现链式调用
js
const STATUS = {
PENDING: "PENDING",
FULFILLED: "FULFILLED",
REJECTED: "REJECTED",
};
class Promise {
constructor(executor) {
this.status = STATUS.PENDING;
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.status === STATUS.PENDING) {
this.status = STATUS.FULFILLED;
this.value = value;
this.onFulfilledCallbacks.forEach((onRejected) => {
onRejected(this.value);
});
}
};
const reject = (reason) => {
if (this.status === STATUS.PENDING) {
this.status = STATUS.REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach((onRejected) => {
onRejected(this.value);
});
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onRejected =
typeof onRejected === "function"
? onRejected
: (err) => {
throw err;
};
if (this.status === STATUS.PENDING) {
this.onFulfilledCallbacks.push(() => onFulfilled);
this.onRejectedCallbacks.push(() => onRejected);
} else if (this.status === STATUS.FULFILLED) {
onFulfilled(this.value);
} else {
onRejected(this.reason);
}
}
}
let promise = new Promise((resolve, reject) => {
resolve("ok");
});
promise.then((value) => {
console.log(value);
});
new Promise((resolve, reject) => {
reject("error");
});4、then 函数链式调用
- 链式调用原理:
- then 函数会返回一个新的 Promise 对象(
promise2) - 这样可以实现 Promise 的链式调用,使代码更加清晰
- 新 Promise 的状态和值由上一个 then 回调的返回值决定
- then 函数会返回一个新的 Promise 对象(
js
then ( onFulfilled, onRejected ) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : ( value ) => value
onRejected = typeof onRejected === 'function' ? onRejected : ( err ) => { throw err };
const promise2 = new Promise( ( resolve, reject ) => {
if ( this.status === STATUS.PENDING ) {
this.onFulfilledCallbacks.push( () => onFulfilled )
this.onRejectedCallbacks.push( () => onRejected )
} else if ( this.status === STATUS.FULFILLED ) {
onFulfilled( this.value )
} else {
onRejected( this.reason )
}
} )
return promise2
}5、then 函数回调返回值处理
- 回调返回值处理规则:
- 异常处理:如果 then 回调执行过程中抛出异常,新 Promise 会变为
rejected状态 - 返回 Promise:如果 then 回调返回一个 Promise,新 Promise 的状态和值会与该 Promise 保持一致
- 返回普通值:如果 then 回调返回一个普通值(非 Promise),新 Promise 会变为
fulfilled状态,值为返回的值 - 无返回值:如果 then 回调没有返回值,新 Promise 会变为
fulfilled状态,值为undefined
- 异常处理:如果 then 回调执行过程中抛出异常,新 Promise 会变为
循环引用案例
js
// 循环引用案例:
const promise2 = new Promise((resolve, reject) => {
resolve("ok");
});
// 循环引用,造成无限死循环需要处理成 reject失败
promise2.then(() => {
return promise2;
});
// 处理异常
if (promise2 === x) {
return reject(new TypeError("循环引用,造成无限死循环"));
}
// ....then 回调返回值是对象,取 then 异常处理
js
const x = {};
Object.defineProperty(x, "then", {
get() {
throw new Error("error");
},
});
// 处理异常
try {
const then = x.then;
} catch (e) {
// 取then错误走下一个失败的then回调
reject(e);
}
// ....如果 then 回调返回值是一个 Promise,并且 resolve 中的值也是一个 Promise,需要递归把值传递下去
js
const promise = new Promise((resolve, reject) => {
resolve("ok");
});
promise.then(() => {
return new Promise((resolve, reject) => {
resolve(
Promise((resolve, reject) => {
resolve("ok");
})
);
});
});
// 处理递归
then.call(
x,
(y) => {
// y有可能还是一个promise,递归到普通值结束
resolvePromise(y, promise2, resolve, reject);
},
(r) => {
// promise失败直接到下一个失败的then回调
reject(r);
}
);
// ....如果 then 回调返回值是不一个规范的 Promise,即可以成功也可以失败,我们需要防止这种情况,不可以逆向
js
const promise = new Promise((resolve, reject) => {
resolve("ok");
});
promise.then(() => {
// 自己实现的Promise即可以成功也可以失败
return new MyPromise((resolve, reject) => {
resolve("ok");
reject("err");
});
});
// 处理不规范的Promise(即可以成功也可以失败)
let called;
try {
const then = x.then;
if (typeof then === "function") {
// 执行promise.then
then.call(
x,
(y) => {
if (called) return;
called = true;
// y有可能还是一个promise,递归到普通值结束
resolvePromise(y, promise2, resolve, reject);
},
(r) => {
if (called) return;
called = true;
// promise失败直接到下一个失败的then回调
reject(r);
}
);
} else {
if (called) return;
called = true;
// 普通值走下一个成功的then回调
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
// 取then错误走下一个失败的then回调
reject(e);
}
// ....6、完整源码实现
js
const STATUS = {
PENDING: "PENDING",
FULFILLED: "FULFILLED",
REJECTED: "REJECTED",
};
/**
*
* @param {*} x then回调的返回值
* @param {*} promise promise2的实例
* @param {*} resolve promise成功
* @param {*} reject promise失败
*/
function resolvePromise(x, promise2, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError("循环引用,造成无限死循环"));
}
// 对象或者function都有可能是Promise
if ((typeof x === "object" && x !== null) || typeof x === "function") {
// 防止别人实现的promise即可以成功,也可以失败
let called;
try {
const then = x.then;
if (typeof then === "function") {
// 执行promise.then
then.call(
x,
(y) => {
if (called) return;
called = true;
// y有可能还是一个promise,递归到普通值结束
resolvePromise(y, promise2, resolve, reject);
},
(r) => {
if (called) return;
called = true;
// promise失败直接到下一个失败的then回调
reject(r);
}
);
} else {
if (called) return;
called = true;
// 普通值走下一个成功的then回调
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
// 取then错误走下一个失败的then回调
reject(e);
}
} else {
// 普通值走下一个成功的then回调
resolve(x);
}
}
class Promise {
constructor(executor) {
this.status = STATUS.PENDING;
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.status === STATUS.PENDING) {
this.status = STATUS.FULFILLED;
this.value = value;
this.onFulfilledCallbacks.forEach((onRejected) => {
onRejected(value);
});
}
};
const reject = (reason) => {
if (this.status === STATUS.PENDING) {
this.status = STATUS.REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach((onRejected) => {
onRejected(reason);
});
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onRejected =
typeof onRejected === "function"
? onRejected
: (err) => {
throw err;
};
const promise2 = new Promise((resolve, reject) => {
if (this.status === STATUS.PENDING) {
this.onFulfilledCallbacks.push(() => {
// 保证promise2实例化完成
setTimeout(() => {
try {
const x = onFulfilled(this.value);
// 处理回调的结果
resolvePromise(x, promise2, resolve, reject);
} catch (e) {
// then回调出新异常直接调用下一个失败的then
reject(e);
}
});
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(x, promise2, resolve, reject);
} catch (e) {
reject(e);
}
});
});
} else if (this.status === STATUS.FULFILLED) {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(x, promise2, resolve, reject);
} catch (e) {
reject(e);
}
});
} else {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(x, promise2, resolve, reject);
} catch (e) {
reject(e);
}
});
}
});
return promise2;
}
catch(onRejected) {
return this.then(null, onRejected);
}
static resolve(val) {
return new Promise((resolve) => {
resolve(val);
});
}
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason);
});
}
static all(promiseArr) {
return new Promise((resolve, reject) => {
if (!Array.isArray(promiseArr)) {
return reject(new TypeError("argument must be an array"));
}
if (promiseArr.length === 0) {
return resolve([]);
}
let result = [];
let total = promiseArr.length;
let count = 0;
function done(i, data) {
result[i] = data;
if (++count == total) {
resolve(result);
}
}
promiseArr.map((p, i) => {
Promise.resolve(p).then((data) => done(i, data), reject);
});
});
}
static race(promiseArr) {
return new Promise((resolve, reject) => {
promiseArr.map((p) => {
p.then((data) => resolve(data), reject);
});
});
}
}
Promise.defer = Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
};
module.exports = Promise;6、测试案例
- 安装
npm install promises-aplus-tests -g - 执行
promises-aplus-tests promise.js(Promise 入口文件路径)

then 交替执行
- 如果有多个 fulfilled 状态的 Promise 实例,同时执行 then 链式调用,then 会交替调用
- 这是编译器的优化,防止一个 Promise 持续占据事件循环
js
Promise.resolve()
.then(() => {
console.log(1);
})
.then(() => {
console.log(2);
})
.then(() => {
console.log(3);
})
.then(() => {
console.log(4);
});
Promise.resolve()
.then(() => {
console.log(10);
})
.then(() => {
console.log(20);
})
.then(() => {
console.log(30);
})
.then(() => {
console.log(40);
});
Promise.resolve()
.then(() => {
console.log(100);
})
.then(() => {
console.log(200);
})
.then(() => {
console.log(300);
})
.then(() => {
console.log(400);
});
// 1 10 100 2 20 200 3 30 300 4 40 400then 返回 Promise
js
Promise.resolve()
.then(() => {
console.log(0);
return Promise.resolve(4); // 相当于多出一个 Promise 实例,会慢2拍
})
.then((res) => {
console.log(res);
});
Promise.resolve()
.then(() => {
console.log(1);
})
.then(() => {
console.log(2);
})
.then(() => {
console.log(3);
})
.then(() => {
console.log(5);
})
.then(() => {
console.log(6);
});
// 0 1 2 3 4 5 6