手写promise几乎每家大厂的必备考题,几回面试都被这个问题坑了,因而花了些时间特地研究了一下,下面是promise实现的思考过程。你们若是不嫌弃,还请往下看:面试
所谓Promise,简单说就是一个容器,里面保存着某个将来才会结束的事件(一般是一个异步操做)的结果。从语法上说,Promise 是一个对象,从它能够获取异步操做的消息。 例如如下一个promise的例子:promise
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操做成功 */){
resolve(value);
} else {
reject(error);
}
});
复制代码
能够看出一个promise的构造函数包含两个方法resolve、reject,同时根据promise+规范可知promise包含三个状态:bash
首先能够根据上面的推测写个构造函数以下:闭包
/**
* 建立三变量记录表示状态
* 用that保存this,避免后期闭包致使this的指向不对
* value 变量用于保存 resolve 或者 reject 中传入的值
* resolvedCallbacks 和 rejectedCallbacks 用于保存 then 中的回调,
* 由于当执行完 Promise 时状态可能仍是等待中,这时候应该把 then 中的回调保存起来用于状态改变时使用
*/
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function myPromise(fn){
const that = this;
that.value = null;
that.status = PENDING; //默认状态
that.fulfilledCallbacks = [];
that.rejectedCallbacks = [];
function resolve(value){
if(that.status === PENDING ){
}
}
function reject(value){
if(that.status === PENDING ){
}
}
// 执行回调函数
try{
fn(resolve, reject)
}catch (e) {
reject(e);
}
}
复制代码
因而思考当在resolve里该干些什么?resolve即执行状态,首先status状态值得变吧,改为fulfilled状态,同时将传入的value值保存起来,以便下面的then会用到,最后得执行回调里面的方法实现回调调用。reject同理,因而按这个思路,就有了:异步
/**
* 建立三变量记录表示状态
* 用that保存this,避免后期闭包致使this的指向不对
* value 变量用于保存 resolve 或者 reject 中传入的值
* resolvedCallbacks 和 rejectedCallbacks 用于保存 then 中的回调,
* 由于当执行完 Promise 时状态可能仍是等待中,这时候应该把 then 中的回调保存起来用于状态改变时使用
*/
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function myPromise(fn){
const that = this;
that.value = null;
that.status = PENDING; //默认状态
that.fulfilledCallbacks = [];
that.rejectedCallbacks = [];
function resolve(value){
if(that.status === PENDING ){
that.status = FULFILLED;
that.value = value;
//执行回调方法
that.fulfilledCallbacks.forEach(myFn => myFn(that.value))
}
}
function reject(value){
if(that.status === PENDING ){
that.status = REJECTED;
that.value = value;
//执行回调方法
that.rejectedCallbacks.forEach(myFn => myFn(that.value))
}
}
// 执行回调函数
try{
fn(resolve, reject)
}catch (e) {
reject(e);
}
}
复制代码
因而promise的构造函数就简陋的完成了,接下来实现then不就大工完成了吗?是否是有些小兴奋~~~函数
考虑到全部的实例都要用到then方法,在then得放在promise的原型链上。当状态是PENDING状态时,该作什么?不执行回调,那就将回调方法分别放入不一样的栈内,等待调用。当状态为FULFILLED或者REJECTED时,则执行响应的方法便可。因而:post
myPromise.prototype.then = function (onFulfilled, onRejected){
let self = this;
//等待状态,则添加回调函数到栈中
if(self.status === PENDING){
self.fulfilledCallbacks.push(()=>{
onFulfilled(self.value);
});
self.rejectedCallbacks.push(()=>{
onRejected(self.value);
})
}
if(self.status === FULFILLED){
onFulfilled(self.value);
}
if(self.status === REJECTED){
onRejected(self.value)
}
}
复制代码
因而一个简单的promise实现以下:优化
/**
* 建立三变量记录表示状态
* 用that保存this,避免后期闭包致使this的指向不对
* value 变量用于保存 resolve 或者 reject 中传入的值
* resolvedCallbacks 和 rejectedCallbacks 用于保存 then 中的回调,
* 由于当执行完 Promise 时状态可能仍是等待中,这时候应该把 then 中的回调保存起来用于状态改变时使用
*/
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function myPromise(fn){
const that = this;
that.value = null;
that.status = PENDING; //默认状态
that.fulfilledCallbacks = [];
that.rejectedCallbacks = [];
function resolve(value){
if(that.status === PENDING ){
that.status = FULFILLED;
that.value = value;
//执行回调方法
that.fulfilledCallbacks.forEach(myFn => myFn(that.value))
}
}
function reject(value){
if(that.status === PENDING ){
that.status = REJECTED;
that.value = value;
//执行回调方法
that.rejectedCallbacks.forEach(myFn => myFn(that.value))
}
}
// 执行回调函数
try{
fn(resolve, reject)
}catch (e) {
reject(e);
}
}
myPromise.prototype.then = function (onFulfilled, onRejected){
let self = this;
//等待状态,则添加回调函数到栈中
if(self.status === PENDING){
self.fulfilledCallbacks.push(()=>{
onFulfilled(self.value);
});
self.rejectedCallbacks.push(()=>{
onRejected(self.value);
})
}
if(self.status === FULFILLED){
onFulfilled(self.value);
}
if(self.status === REJECTED){
onRejected(self.value)
}
}
let p = new thePromise((resolve, reject)=>{
console.log('hello');
resolve(5);
});
p.then((res)=>{
console.log(res);
})
p.then(()=>{
console.log('jj');
})
复制代码
结果以下: ui
但是有没有发现then里并无返回一个promise,并不符合规范,因此能够对promise进行部分优化。this
根据promise+规范改造promise,传给then的应该是个promise,以下: resolve 和reject的改造:
function resolve(value) {
if(value instanceof myPromise){
return value.then(resolve, reject);
}
setTimeout(()=>{
that.status = FULFILLED;
that.value = value;
//执行会回调方法
that.fulfilledCallbacks.forEach(myFn => myFn(that.value))
},0)
}
function reject(value) {
setTimeout(()=>{
that.status = REJECTED;
that.value = value;
//执行会回调方法
that.rejectedCallbacks.forEach(myFn => myFn(that.value))
}, 0);
}
复制代码
接下来改造then方法: 首先咱们须要新增一个变量 promise2,由于每一个 then 函数都须要返回一个新的 Promise 对象,该变量用于保存新的返回对象,因而:
myPromise.prototype.then = function (onFulfilled, onRejected) {
let self = this;
let promise2 = null;
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
onRejected = typeof onRejected === 'function' ? onRejected : r => {throw r}
//等待状态,则添加回调函数到栈中
if(self.status === PENDING){
return (promise2 = new myPromise((resolve, reject)=>{
self.fulfilledCallbacks.push(()=>{
try {
let x = onFulfilled(self.value);
resolutionProduce(promise2, x, resolve, reject);
}catch (e) {
reject(e)
}
});
self.rejectedCallbacks.push(()=>{
try {
let x = onRejected(self.value);
resolutionProduce(promise2, x, resolve, reject);
}catch (e) {
reject(e);
}
onRejected(self.value);
});
}));
}
if(self.status === FULFILLED){
return(promise2 = new myPromise((resolve, reject)=>{
setTimeout(()=>{
try {
let x = onFulfilled(self.value);
resolutionProduce(promise2, x, resolve, reject);
}catch (e) {
reject(e);
}
}, 0)
}));
}
if(self.status === REJECTED){
return (promise2 = new myPromise((resolve, reject)=>{
setTimeout(()=>{
try {
let x = onRejected(self.value);
resolutionProduce(promise2, x, resolve, reject)
}catch (e) {
reject(e);
}
},0)
}));
}
}
复制代码
思路跟以前基本一致,只是说把以前返回值改为promise,同时捕获异常,在status状态为FULFILLED或者REJECTED的时候执行得加上异步setTimeout包裹。 接下来完成最核心的resolutionProduce函数:
let p = new myPromise((resolve, reject) => {
resolve(1)
})
let p1 = p.then(value => {
return p1
})
复制代码
if (x instanceof MyPromise) {
x.then(function(value) {
resolutionProcedure(promise2, value, resolve, reject)
}, reject)
}
复制代码
这里的代码是彻底按照规范实现的。若是 x 为 Promise 的话,须要判断如下几个状况:
function resolutionProduce(promise, x, resolve, reject){
if(promise === x){
return reject(new TypeError('Error'));
}
let called = false;
if(x !== null && (typeof x === 'object' || typeof x === 'function')){
try {
let then = x.then;
if(typeof then === 'function'){
then.call(x, y=>{
if(called) return;
called = true;
resolutionProduce(promise2, y, resolve, reject )
}, e =>{
if(e) return;
called = true;
reject(e);
})
}else {
resolve(x);
}
}catch (e) {
if(called) return;
called = true;
reject(e);
}
}else {
resolve(x);
}
}
复制代码
以上即是promise的简单实现,下回有时间将把catch与all、race等方法实现,敬请期待 未完待续。。。 参考: juejin.im/post/5b88e0…