主要由三部分来实现,promise构造函数,then方法和promise处理程序(判断返回值或者决议的值)
promise构造函数
function myPromise(executor) {
this.status = "pending";
this.data = null;
this.successCbArr = [];//收集fulfilled后的回调
this.failCbArr = [];//收集rejected后的回调
const _this = this;//保存this,因为resolve是独立函数调用,直接使用this会是window
function resolve(value) {
//settimeout为了保证在resolve后面的同步代码会先执行打印,
setTimeout(() => {
if (_this.status === "pending") {
_this.status = "fulfilled";
_this.data = value;
_this.successCbArr.forEach((cb) => {
cb();
});
}
});
}
function reject(err) {
setTimeout(() => {
if (_this.status === "pending") {
_this.status = "rejected";
_this.data = err;
_this.failCbArr.forEach((cb) => {
cb();
});
}
});
}
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
resolve和reject里面的setTimeout是为了让resolve(xxx)或者reject(xxx)后面的代码先执行
例如下面,222会比‘1111’先打印
const p=new Promise((res,rej)=>{
res('1111')
console.log(2222)
}
)
p.then(res=>{
console.log(res)
})
then方法
//2.then回调处理
myPromise.prototype.then = function (successCb, failCb) {
let promise2;
promise2 = new myPromise((resolve, reject) => {
if (this.status === "fulfilled") {
setTimeout(() => {
if (typeof successCb === "function") {
//这里的settimeout,是为了能够让then调用地方的后面的同步代码先执行打印
//因为then的回调属于微任务,
//只要执行回调函数的地方都要try catch出现错误立即reject掉
try {
const x = successCb(this.data);
promiseResolutionProcedure(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
} else {
//如果不是函数,则这个then的结果必须跟then的调用者的决议值一样。下面代码类似
resolve(this.data);
}
});
} else if (this.status === "rejected") {
setTimeout(() => {
if (typeof failCb === "function") {
try {
const x = failCb(this.data);
promiseResolutionProcedure(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
} else {
reject(this.data);
}
});
} else if (this.status === "pending") {//如果是pending,此时要将会回调进行收集,等到由结果在进行执行
//pengding状态
this.successCbArr.push(() => {
if (typeof successCb === "function") {
try {
const x = successCb(this.data);
//根据回调函数返回值,决定promise2的状态是fulfilled还是rejected
promiseResolutionProcedure(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
} else {
resolve(this.data);
}
});
this.failCbArr.push(() => {
if (typeof failCb === "function") {
try {
const x = failCb(this.data);
promiseResolutionProcedure(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
} else {
reject(this.data);
}
});
}
});
//为了链式调用,必须返回promise对象
return promise2;
};
对于上面fulfilled判断里面或者rejected判断里面的setTimeout,是为了让在then调用的地方后面的代码,能够先执行,因为then的回调属于微任务。
例如下面
const p = new Promise((res, rej) => {
res("1111");
console.log(2222);
});
p.then((res) => {
console.log(res);
});
console.log(333);
//打印结果
2222
333
1111
当执行到then的时候,由于上面的promise也就决议了,所以在调用then函数时会进入this.status === "fulfilled"的判断中,并执行里面的代码,但是此时then函数后面还有同步代码,所以需要将then函数的执行延后。
promise处理程序
//3.promise处理程序,处理返回值或者决议一个thenable的对象或函数时
function promiseResolutionProcedure(promise2, x, resolve, reject) {
//1.首先判断循环引用
if (promise2 === x) {
return reject(new TypeError("存在循环引用"));
}
//2.判断返回值x是不是promise实例
//例子
// p.then(res=>{
// return new myPromise((res,rej)=>{
// res(111)
// })
// })
if (x instanceof myPromise) {
//2.1判断这个实例的状态,来决定promise2的结果
if (x.status === "pending") {
//pending时,需要等到他的结果(fulfilled或rejected)出来在进一步判断
x.then(function (value) {
promiseResolutionProcedure(promise2, value, resolve, reject);
}, reject);
} else if (x.status === "fulfilled") {
resolve(x.data);
} else if (x.status === "rejected") {
//否决状态,rejected
reject(x.data);
}
return;
}
//3.判断是否是一个对象或者函数
if (x && (typeof x === "object" || typeof x === "function")) {
//为了防止thenable里面的两个回调函数调用多次,一旦resolve或reject后,状态值就不改变了
let isCalled = false;
try {
let then = x.then;
if (typeof then === "function") {
//这里需要调用thenable方法,得状态值,来决定promise2的状态
then.call(
x,
function resolvePromise(value) {
if (isCalled) return;
isCalled = true;
return promiseResolutionProcedure(promise2, value, resolve, reject);
},
function rejectPromise(err) {
if (isCalled) return;
isCalled = true;
return reject(err);
}
);
} else {
resolve(x);
}
} catch (error) {
if (isCalled) return; //如果已经resolve或reject过了,或者已经发生过异常了,则后面调用时产生的异常忽略
isCalled = true;
reject(error);
}
} else {
resolve(x);
}
}
thenable对象:是指一个对象,虽然它可能不是真正的 Promise 实例,但它具有类似于 Promise 的特性,即它有一个 then
方法,可以被用于处理异步操作。
例
// 定义一个 thenable 对象
const thenableObject = {
then: function(resolve, reject) {
setTimeout(function() {
resolve("Hello from thenable!");
}, 1000);
}
};
// 使用 Promise 处理 thenable 对象
const promise = new Promise(function(resolve, reject) {
resolve(thenableObject);
});
promise.then(function(result) {
console.log(result); // 输出: Hello from thenable!
});
设置isCalled的目的:一旦当resolve或reject后,后面再调用resolve都没有用了,结果已经确定了
例如上面的代码改写如下
const thenableObject = {
then: function(resolve, reject) {
setTimeout(function() {
resolve("Hello from thenable!");
resolve("Hello ");//后面又调用了resolve或者reject
reject('error');
}, 1000);
}
};
// 使用 Promise 处理 thenable 对象
const promise = new Promise(function(resolve, reject) {
resolve(thenableObject);
});
promise.then(function(result) {
console.log(result); // 输出: Hello from thenable!
});
上面result打印的结果仍然是 Hello from thenable!
代码测试
将我们上面写的代码导出,并在下面这个test.js文件中导入
//test.js
const Promise = require("./promise2.js");
Promise.deferred = function () {
const obj = {};
obj.promise = new Promise(function (resolve, reject) {
obj.resolve = resolve;
obj.reject = reject;
});
return obj;
};
module.exports = Promise;
运行测试命令
npx promises-aplus-tests test.js
结果: