原生Promise
- 首先,我们用原生的Promise实现一个简单的promise:
js
const text = new Promise((resolve, reject) => {
resolve("成功!!");
});
text.then(
(res) => {
console.log(res);
},
(err) => {}
);
运行上述代码,会进入promise的成功态resolve,输出"成功!!"
手写一个简单的Promise
接下来,我们自己手写一个Promise。
js
// 定义promise的三个状态
const RESOLVE = "resolved";
const REJECT = "rejected";
const PENDING = "pending";
class ZZHPromise {
status = PENDING;
result = undefined;
reason = undefined;
constructor(excution) {
// 成功态
const resolve = (result) => {
if (this.status === PENDING) {
this.result = result;
this.status = RESOLVE;
}
};
// 失败态
const reject = (reason) => {
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECT;
}
};
excution(resolve, reject);
}
// then方法里有两个参数,分别是两个方法
then(onResolved, onRejected) {
if (this.status === RESOLVE) {
onResolved(this.result);
}
if (this.status === REJECT) {
onRejected(this.reason);
}
}
}
module.exports = ZZHPromise;
首先定义了三个静态常量,为promise的三种状态。并且定义了resolve和reject两个函数,分别代表成功态和失败态。
为什么要判断状态为pending
才会执行呢?这是因为,在promise中,一个流程中只能执行resolve
或reject
,所以当执行完一种状态后,status被修改为当前状态,则promise就不会再继续执行另一个状态,才能达到promise的要求。
接下来来看then方法。then方法中会传入两个参数(onResolved, onRejected)为两个方法,分别代表成功态运行方法和失败态运行方法。在then方法中,是用status
状态去判断现在应该执行哪个方法。
这样,我们就实现了一个简单的promise。在text文件中引入我们自己的promise,调用一下,输出"成功!!",说明这个简单的promise是没有问题的。
异步处理promise
我们看一下上图的代码,由于原生Promise是异步的,所以代码会优先执行同步任务console.log("我先执行");
再执行Promise。但是如果用我们自己手写的Promise,就会先运行promise,再运行console.log("我先执行");
。
所以,需要让我们自己的promise也变成异步的。
其实很简单,我们只需要把onResolved
和onRejected
放在setTimeout
中,让他们变成异步的。这样再来看一下输出结果,就会先输出"我先执行",再输出promise。
再来看一个新的问题,假如我们请求一个接口,在1s后才返回。这时,什么都没有输出。
这是因为,resolve会在1s后执行。而then并不会等待,而是优先执行,所以在then执行时,当前status
还是pending。所以不会输出任何东西。
怎么解决呢?
我们可以用一个发布订阅模式,定义两个数组,onResolvedArr
和onRejectedArr
。当状态为pending
时,将成功或失败的函数,推入数组中。并在方法中,循环这个数组。代码如下:
js
// 定义promise的三个状态
const RESOLVE = "resolved";
const REJECT = "rejected";
const PENDING = "pending";
class ZZHPromise {
status = PENDING;
result = undefined;
reason = undefined;
onResolvedArr = [];
onRejectedArr = [];
constructor(excution) {
// 成功态
const resolve = (result) => {
if (this.status === PENDING) {
this.result = result;
this.status = RESOLVE;
this.onResolvedArr.map((fn) => fn());
}
};
// 失败态
const reject = (reason) => {
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECT;
this.onRejectedArr.map((fn) => fn());
}
};
excution(resolve, reject);
}
// then方法里有两个参数,分别是两个方法
then(onResolved, onRejected) {
if (this.status === RESOLVE) {
setTimeout(() => {
onResolved(this.result);
}, 0);
}
if (this.status === REJECT) {
setTimeout(() => {
onRejected(this.reason);
}, 0);
}
if (this.status === PENDING) {
this.onResolvedArr.push(() => onResolved(this.result));
this.onRejectedArr.push(() => onRejected(this.reason));
}
}
}
module.exports = ZZHPromise;
这样,就会在1秒中之后,输出"成功!!"
链式调用Promise
我们都知道,promise是可以链式调用的。但是,我们自己的promise,由于现在是没有返回值的,返回值为undefined,所以是无法链式调用的。
所以我们应该返回一个promise:
js
// 定义promise的三个状态
const RESOLVE = "resolved";
const REJECT = "rejected";
const PENDING = "pending";
class ZZHPromise {
status = PENDING;
result = undefined;
reason = undefined;
onResolvedArr = [];
onRejectedArr = [];
constructor(excution) {
// 成功态
const resolve = (result) => {
if (this.status === PENDING) {
this.result = result;
this.status = RESOLVE;
this.onResolvedArr.map((fn) => fn());
}
};
// 失败态
const reject = (reason) => {
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECT;
this.onRejectedArr.map((fn) => fn());
}
};
excution(resolve, reject);
}
// then方法里有两个参数,分别是两个方法
then(onResolved, onRejected) {
const newPromise = new ZZHPromise((resolve, reject) => {
if (this.status === RESOLVE) {
setTimeout(() => {
onResolved(this.result);
}, 0);
}
if (this.status === REJECT) {
setTimeout(() => {
onRejected(this.reason);
}, 0);
}
if (this.status === PENDING) {
this.onResolvedArr.push(() => onResolved(this.result));
this.onRejectedArr.push(() => onRejected(this.reason));
}
});
return newPromise;
}
}
module.exports = ZZHPromise;
这样,就可以进行链式调用,不过我们发现,then里面的res一直没有调用,这是因为resolve一直没有执行。所以,我们需要再定义一个方法去处理。并且做一下异常处理。
以下就是全部的promise代码:
js
// 定义promise的三个状态
const RESOLVE = "resolved";
const REJECT = "rejected";
const PENDING = "pending";
const handlePromise = (result, newPromise, resolve, reject) => {
if (result === newPromise) {
throw new Error("can not return oneself");
}
// 判断result(promise的返回值)的类型
if (
(typeof result === "object" && typeof result !== null) ||
typeof result === "function"
) {
// 加一把锁,防止有的第三方promise会resolve, reject两个都执行。
let lock = false;
try {
const then = result.then;
// 因为有可能promise的then方法里返回的then还是一个promise,所以要当then不是一个promise时,再resolve出去.
if (typeof then === "function") {
then.call(
result,
(r) => {
if (lock) return;
handlePromise(r, newPromise, resolve, reject);
lock = true;
},
(e) => {
if (lock) return;
reject(e);
lock = true;
}
);
} else {
resolve(result);
}
} catch (error) {
reject(error);
}
} else {
resolve(result);
}
};
class ZZHPromise {
status = PENDING;
result = undefined;
reason = undefined;
onResolvedArr = [];
onRejectedArr = [];
constructor(excution) {
// 成功态
const resolve = (result) => {
if (this.status === PENDING) {
this.result = result;
this.status = RESOLVE;
this.onResolvedArr.map((fn) => fn());
}
};
// 失败态
const reject = (reason) => {
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECT;
this.onRejectedArr.map((fn) => fn());
}
};
try {
excution(resolve, reject);
} catch (error) {
reject(error);
}
}
// then方法里有两个参数,分别是两个方法
then(onResolved, onRejected) {
onResolved = typeof onResolved === "function" ? onResolved : (data) => data;
onRejected =
typeof onRejected === "function"
? onRejected
: (err) => {
throw new Error(err);
};
const newPromise = new ZZHPromise((resolve, reject) => {
if (this.status === RESOLVE) {
setTimeout(() => {
try {
const result = onResolved(this.result);
handlePromise(result, newPromise, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
if (this.status === REJECT) {
setTimeout(() => {
try {
const result = onRejected(this.reason);
handlePromise(result, newPromise, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
if (this.status === PENDING) {
this.onResolvedArr.push(() => {
try {
const result = onResolved(this.result);
handlePromise(result, newPromise, resolve, reject);
} catch (error) {
reject(error);
}
});
this.onRejectedArr.push(() => {
try {
const result = onRejected(this.reason);
handlePromise(result, newPromise, resolve, reject);
} catch (error) {
reject(error);
}
});
}
});
return newPromise;
}
catch(onRejected) {
return this.then(undefined, onRejected);
}
}
module.exports = ZZHPromise;