1. 手搓 Promise
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";
function MyPromise(fn) {
// 保留初始化状态
var self = this;
// 初始化状态
this.state = PENDING;
// 用于保留 resolve 或者 rejected 传入的值
this.value = null;
// 用于保留 resolve 的回调函数
this.resolvedCallbacks = [];
// 用于保留 reject 的回调函数
this.rejectedCallbacks = [];
// 状态转变为 resolved 办法
function resolve(value) {
// 判断传入元素是否为 Promise 值,如果是,则状态扭转必须期待前一个状态扭转后再进行扭转
if (value instanceof MyPromise) {return value.then(resolve, reject);
}
// 保障代码的执行程序为本轮事件循环的开端
setTimeout(() => {
// 只有状态为 pending 时能力转变,if (self.state === PENDING) {
// 批改状态
self.state = RESOLVED;
// 设置传入的值
self.value = value;
// 执行回调函数
self.resolvedCallbacks.forEach(callback => {callback(value);
});
}
}, 0);
}
// 状态转变为 rejected 办法
function reject(value) {
// 保障代码的执行程序为本轮事件循环的开端
setTimeout(() => {
// 只有状态为 pending 时能力转变
if (self.state === PENDING) {
// 批改状态
self.state = REJECTED;
// 设置传入的值
self.value = value;
// 执行回调函数
self.rejectedCallbacks.forEach(callback => {callback(value);
});
}
}, 0);
}
// 将两个办法传入函数执行
try {fn(resolve, reject);
} catch (e) {
// 遇到谬误时,捕捉谬误,执行 reject 函数
reject(e);
}
}
MyPromise.prototype.then = function(onResolved, onRejected) {
// 首先判断两个参数是否为函数类型,因为这两个参数是可选参数
onResolved =
typeof onResolved === "function"
? onResolved
: function(value) {return value;};
onRejected =
typeof onRejected === "function"
? onRejected
: function(error) {throw error;};
// 如果是期待状态,则将函数退出对应列表中
if (this.state === PENDING) {this.resolvedCallbacks.push(onResolved);
this.rejectedCallbacks.push(onRejected);
}
// 如果状态曾经凝固,则间接执行对应状态的函数
if (this.state === RESOLVED) {onResolved(this.value);
}
if (this.state === REJECTED) {onRejected(this.value);
}
};
2. 手搓 Promise.then
then
办法返回一个新的 promise
实例,为了在 promise
状态发生变化时(resolve
/ reject
被调用时)再执行 then
里的函数,咱们应用一个 callbacks
数组先把传给 then 的函数暂存起来,等状态扭转时再调用。
那么,怎么保障后一个 **then**
里的办法在前一个 **then**
(可能是异步)完结之后再执行呢?
咱们能够将传给 then
的函数和新 promise
的 resolve
一起 push
到前一个 promise
的 callbacks
数组中,达到承前启后的成果:
- 承前:以后一个
promise
实现后,调用其resolve
变更状态,在这个resolve
里会顺次调用callbacks
里的回调,这样就执行了then
里的办法了 - 启后:上一步中,当
then
里的办法执行实现后,返回一个后果,如果这个后果是个简略的值,就间接调用新promise
的resolve
,让其状态变更,这又会顺次调用新promise
的callbacks
数组里的办法,周而复始。。如果返回的后果是个promise
,则须要等它实现之后再触发新promise
的resolve
,所以能够在其后果的then
里调用新promise
的resolve
then(onFulfilled, onReject){
// 保留前一个 promise 的 this
const self = this;
return new MyPromise((resolve, reject) => {
// 封装前一个 promise 胜利时执行的函数
let fulfilled = () => {
try{const result = onFulfilled(self.value); // 承前
return result instanceof MyPromise? result.then(resolve, reject) : resolve(result); // 启后
}catch(err){reject(err)
}
}
// 封装前一个 promise 失败时执行的函数
let rejected = () => {
try{const result = onReject(self.reason);
return result instanceof MyPromise? result.then(resolve, reject) : reject(result);
}catch(err){reject(err)
}
}
switch(self.status){
case PENDING:
self.onFulfilledCallbacks.push(fulfilled);
self.onRejectedCallbacks.push(rejected);
break;
case FULFILLED:
fulfilled();
break;
case REJECT:
rejected();
break;
}
})
}
留神:
- 间断多个
then
里的回调办法是同步注册的,但注册到了不同的callbacks
数组中,因为每次then
都返回新的promise
实例(参考下面的例子和图) - 注册实现后开始执行构造函数中的异步事件,异步实现之后顺次调用
callbacks
数组中提前注册的回调
3. 手搓 Promise.all
1) 外围思路
- 接管一个 Promise 实例的数组或具备 Iterator 接口的对象作为参数
- 这个办法返回一个新的 promise 对象,
- 遍历传入的参数,用 Promise.resolve()将参数 ” 包一层 ”,使其变成一个 promise 对象
- 参数所有回调胜利才是胜利,返回值数组与参数程序统一
- 参数数组其中一个失败,则触发失败状态,第一个触发失败的 Promise 错误信息作为 Promise.all 的错误信息。
2)实现代码
一般来说,Promise.all 用来解决多个并发申请,也是为了页面数据结构的不便,将一个页面所用到的在不同接口的数据一起申请过去,不过,如果其中一个接口失败了,多个申请也就失败了,页面可能啥也出不来,这就看以后页面的耦合水平了
function promiseAll(promises) {return new Promise(function(resolve, reject) {if(!Array.isArray(promises)){throw new TypeError(`argument must be a array`)
}
var resolvedCounter = 0;
var promiseNum = promises.length;
var resolvedResult = [];
for (let i = 0; i < promiseNum; i++) {Promise.resolve(promises[i]).then(value=>{
resolvedCounter++;
resolvedResult[i] = value;
if (resolvedCounter == promiseNum) {return resolve(resolvedResult)
}
},error=>{return reject(error)
})
}
})
}
// test
let p1 = new Promise(function (resolve, reject) {setTimeout(function () {resolve(1)
}, 1000)
})
let p2 = new Promise(function (resolve, reject) {setTimeout(function () {resolve(2)
}, 2000)
})
let p3 = new Promise(function (resolve, reject) {setTimeout(function () {resolve(3)
}, 3000)
})
promiseAll([p3, p1, p2]).then(res => {console.log(res) // [3, 1, 2]
})
4. 手搓 Promise.race
该办法的参数是 Promise 实例数组, 而后其 then 注册的回调办法是数组中的某一个 Promise 的状态变为 fulfilled 的时候就执行. 因为 Promise 的状态 只能扭转一次, 那么咱们只须要把 Promise.race 中产生的 Promise 对象的 resolve 办法, 注入到数组中的每一个 Promise 实例中的回调函数中即可.
Promise.race = function (args) {return new Promise((resolve, reject) => {for (let i = 0, len = args.length; i < len; i++) {args[i].then(resolve, reject)
}
})
}