实现一个简单的Promise

  • 整体结构:
  • 思路是最关键的

表面上看起来:Promise最基础的功能就是在resolve之后执行实例原型上的then中传入的方法

一般情况下,我们是这样使用Promise的

const a = new Promise(#1 (resolve) => {
setTimeout(() => {
#2 resolve(123);
}, 1000);
});
#3 a.then(#4 (v) => {
console.log(v); //////123
});

我们可以把then函数理解成是一个函数收集器,先将你预先想执行的函数在promise内部注册,在resolve或reject之后再逐个调用

执行顺序: #1->#3->#2->#4

但是也存在这样一种情况,Promise传入函数不是异步函数,比如

const a = new Promise(#1 (resolve) => {
#2 resolve(123);
});
#3 a.then(#4 (v) => {
console.log(v); //////123
});

立即执行#1之后马上就resolve了

执行顺序: #1->#2->#3->#4

那么按照之前说的,then收集将要执行的函数,resolve时再调用,现在resolve在then之前就执行了,那还怎么正常执行#4

解决办法

先不管具体逻辑部分,用setTimeout方法将真正要执行的部分包裹一下,押入setTimeout队列,等待普通的任务队列中的任务执行完才开始按顺序执行积累在setTimeout中的任务,所以这样封装之后顺序又回到了原来的状态

执行顺序: #1->#3->#2->#4

  • 状态

promise内部的状态我把它分为三种情况“pending”,“resolved”,“rejected”

在初始化Promise时初始状态是“pending”,然后在执行then收集函数的时候,通过状态来判断执行的操作

如果是pending,将函数押栈,否则直接执行传进来的函数

  • 链式调用

promise的精髓和弊端都是链式调用,链式的实现方式很简单,再返回一个新实例即可

  • 传入参数是Promise的情况

在执行时判断一下即可,如果是返回的是Promise,则调用Promise.then方法,将外部的resolve作为then方法的第一个参数,这样即可递归至所有返回结果不为promise为止

实现了基本的promise后就可以编写一些api函数了

  • promise.all
arg.callee.prototype.all = function (entries) {
return new arg.callee(function (resolve, reject) {
var resolvedCounter = [];
for (var i = 0; i < entries.length; i++) {
(function (cur) {
arg.callee.resolve(entries[i]).then((v) => {
resolvedCounter[i] = v;
if (resolvedCounter.length === entries.length) {
return resolve(resolvedCounter);
}
}, function (reason) {
return reject(reason);
});
})(i);
}
});
};
  • promise.race
arg.callee.race = function (entries) {
return new arg.callee(function (resolve, reject) {
for (var i = 0; i < entries.length; i++) {
arg.callee.resolve(entries[i]).then((v) => {
return resolve(v);
}, function (reason) {
return reject(reason);
});
}
});
};

function MyPromise(fn) {
this.status = 'pending';
this.value = null;
this.reason = null;
var self = this;
var resDeferreds = [];
var rejDeferreds = [];
var arg = arguments;
var resolve = function (val) {
if (self.status !== 'pending') {
return;
}
setTimeout(function () {
self.value = val;
self.status = "resolved";
resDeferreds.forEach(function (deferred) {
deferred(self.value);
});
}, 0);
};
var reject = function (val) {
if (self.status !== 'pending') {
return;
}
setTimeout(function () {
self.reason = val;
self.status = "rejected";
rejDeferreds.forEach(function (deferred) {
deferred(self.reason);
});
}, 0);
};
arg.callee.prototype.then = function (resolved, rejected) {
resolved = typeof resolved === 'function' ? resolved : function (v) {
return v;
};
rejected = typeof rejected === 'function' ? rejected : function (r) {
throw r;
};
return new arg.callee(function (resolve, reject) { //返回一个新的promise
function resHandle(value) { //成功
setTimeout(function () {
var ret = resolved(self.value);
if (ret instanceof arg.callee) { //判断 then中的 返回的是否是promise对象,如果是注册then方法
ret.then(resolve, reject);
} else {
resolve(ret);
}
});
}

function rejHandle(reason) { //失败
setTimeout(function () {
var ret = rejected(self.value);
if (ret instanceof arg.callee) { //判断 then中的 返回的是否是promise对象,如果是注册then方法
ret.then(resolve, reject);
} else {
reject(ret);
}
});

}

if (self.status === 'pending') {
resDeferreds.push(resHandle);
rejDeferreds.push(rejHandle);
}
if (self.status === 'resolved') {
resHandle(self.value);
}
if (self.status === 'rejected') {
rejHandle(self.reason);
}
});
};
arg.callee.resolve = function (value) {
return new arg.callee(function (res, rej) {
if (value instanceof arg.callee) {
value.then(res, rej);
} else {
resolve(value);
}
});
};
arg.callee.all = function (entries) {
return new arg.callee(function (resolve, reject) {
var resolvedCounter = [];
for (var i = 0; i < entries.length; i++) {
(function (cur) {
arg.callee.resolve(entries[i]).then((v) => {
resolvedCounter[i] = v;
if (resolvedCounter.length === entries.length) {
return resolve(resolvedCounter);
}
}, function (reason) {
return reject(reason);
});
})(i);
}
});
};
arg.callee.race = function (entries) {
return new arg.callee(function (resolve, reject) {
for (var i = 0; i < entries.length; i++) {
arg.callee.resolve(entries[i]).then((v) => {
return resolve(v);
}, function (reason) {
return reject(reason);
});
}
});
};
fn(resolve, reject);
};

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注