前言
Promis方面的知识点一直都是前端面试的重点和难点,手写Promise更是对前端工程师的一大挑战。今天来写并讲一下一个通俗易懂的版本。话不多说,勇敢猿猿,不怕困难!!!!
先来点简单的
- 先写一个自执行函数,然后把自己写的Promise函数暴露出去,这样window中的Promise就是我们写的Promise。大家都知道,在创建Promise实例的时候,必须传进去一个函数,否则会报错,所以在函数里第一步就是判断传进拉的exeutor参数是否是函数,如果不是函数就抛出该错误。
(function () {
function Promise(executor) {
//实例化promise的时候没有传参数,保证executor必须是一个函数
if (typeof executor !== 'function') {
throw new TypeError('Promise resolver' + executor + 'is not a function ');
}
}
// 将自己写的promise暴露出去
window.Promise = Promise;
})();
let p1 = new Promise((resolve, reject) => {});
- 然后传进来的executor函数会立即执行,并且executor函数有两个参数函数,分别是resolve和reject,这连个函数参数分别可以改变Promise实例的结果(PromiseResult )和状态(PromiseState )。Promise有三种状态,成功态(fulfilled),失败态(rejected),等待态(pending)。刚开始Promise都是等待态。
(function () {
function Promise(executor) {
//实例化promise的时候没有传参数,保证executor必须是一个函数
if (typeof executor !== 'function') {
throw new TypeError('Promise resolver' + executor + 'is not a function ');
}
//self:存储的是promise实例
var self = this;
self.PromiseState = 'pending';
self.PromiseResult = undefined;
executor(resolve, reject);
}
// 将自己写的promise暴露出去
window.Promise = Promise;
})();
let p1 = new Promise((resolve, reject) => {
resolve('ok')
});
- resolve函数是将Promise实例由等待态变为成功态,reject函数是将Promise由等待态变为失败态;并将传进resolve函数和reject函数的参数赋给Promise实例的结果(PromiseResult)。但是别忘了,成功态和失败态不能互相转化,所以要函数执行后第一件事是判断当前的Promise实例是否是等待态。
3.1 还有一点特别注意,如果executor函数报错,那么Promise实例也会进入失败态,那么就用try catch来捕获executor函数的报错,让其报错时,执行reject函数。
(function () {
function Promise(executor) {
//实例化promise的时候没有传参数,保证executor必须是一个函数
if (typeof executor !== 'function') {
throw new TypeError('Promise resolver' + executor + 'is not a function ');
}
//self:存储的是promise实例
var self = this;
self.PromiseState = 'pending';
self.PromiseResult = undefined;
var resolve=function resolve(value){
if (self.PromiseState === 'pending') {
self.PromiseState = 'fulfilled';
self.PromiseResult = value;
}
}
var reject=function resolve(reason){
if (self.PromiseState === 'pending') {
self.PromiseState = 'rejected';
self.PromiseResult = reason;
}
}
try {
executor(resolve, reject);
} catch (error) {
reject(err);
}
}
// 将自己写的promise暴露出去
window.Promise = Promise;
})();
let p1 = new Promise((resolve, reject) => {
resolve('ok')
});
坚持住!!往下看
- Promise实例有.then方法和.catch方法来处理实例在成功态和失败态时对后续代码的处理,那我们把这些写到Promise的原型上
4.1 下面写原型的方式,别忘了把constructor(构造函数指回Promise) - 首先 .then方法有两种情况,一种是知道立即知道Promise实例的情况,就比如在executor函数里同步执行代码,立刻可以知道实例是成功态还是失败态,这样就可以通过实例的PromiseState做出判断,调用哪个函数;另一种是不能立即知道实例的状态,就比如executor函数中执行了一个1s的定时器,不能马上得出实例的状态,这时我们应该把执行的函数存起来,执行resolve/reject函数时,通知其执行。
- 其次,.then方法是异步的执行的,所以不管是成功还是失败的处理函数,放在定时器里执行。
function Promise(executor) {
.....
self.onFulfilledCallbacks = [];
self.onRejectedCallbacks = [];
.....
}
Promise.prototype = {
constructor: Promise,
then: function (onfulfilled, onrejected) {
var self = this;
switch (self.PromiseState) {
//知道状态的情况
case 'fullfilled':
setTimeout(function () {
onfulfilled(self.PromiseResult);
});
break;
case 'rejected':
setTimeout(function () {
onrejected(self.PromiseResult);
});
break;
//不知道状态的情况
default:
self.onFulfilledCallbacks.push(onfulfilled);
self.onRejectedCallbacks.push(onrejected);
break;
}
}
}
- 执行resolve/reject,立即更改状态信息,但不会立即通知方法执行(异步效果),onFulfilledCallbacks中保存着成功时的处理函数,onRejectedCallbacks中保存这失败时的处理函数,等executor函数中的异步函数执行完,resolve/reject执行时遍历这个两个数组,修改Promise实例的结果。
function resolve(value) {
if (self.PromiseState === 'pending') {
....
setTimeout(function () {
for (var i = 0; i < self.onFulfilledCallbacks.length; i++) {
let itemFunc = self.onFulfilledCallbacks[i];
if (typeof itemFunc === 'function') {
itemFunc(self.PromiseResult);
}
}
});
}
}
function reject(reason) {
if (self.PromiseState === 'pending') {
....
setTimeout(function () {
for (var i = 0; i < self.onRejectedCallbacks.length; i++) {
let itemFunc = self.onRejectedCallbacks[i];
if (typeof itemFunc === 'function') {
itemFunc(self.PromiseResult);
}
}
});
}
}
- 到这点,面试时写到这点基本就可以了,Promise基本的特点基本完成了;Promise函数立即执行,resolve/reject/.then这样函数异步执行,只能有等待态转为成功态或者失败态。是不是很简单…