前言
Promise 是 JavaScript 中用于异步操作非常重要的一个构造函数,那么它是怎么实现的呢?
下面用原生 JavaScript 来实现一个简易版的 Promise,用来实现以下代码。
function Promise(???){
???
return ???
}
var promise = new Promise(function(resolve, reject) {
setTimeout(() => {
resolve('hello');
}, 3000);
});
promise.then(
val => {
console.log('第一次成功', val);// 输出 第一次成功 hello
},
val => {
console.log('第一次失败', val);
}
);
复制代码
实现
用过 Promise 的朋友都知道,Promise 要接受一个函数 fn 并调用它,Promise 还应该有一个表示状态( pending, resolved, rejected )的属性值 status,一个 value 存储 then 回调时传的值,还有一个 then 方法。其他方法暂时不考虑了。
function Promise(fn) {
//初始 status 为 peding
let status = 'pending';
//存储 then 回调值
let value;
//存储 then 的两个参数
let onResolvedCallback;
let onRejectedCallback;
//设置 fn 的 resolve 函数
function resolve(data) {
//将 status 变成 fulfilled
status = 'fulfilled';
//存储回调函数的值
value = data;
toDoThen(onResolvedCallback, onRejectedCallback);
}
//设置 fn 的 reject 函数
function reject(data) {
//将 status 变成 rejected
status = 'rejected';
//存储回调函数的值
value = data;
toDoThen(onResolvedCallback, onRejectedCallback);
}
//设置 resolve 或 reject 时的执行体
function toDoThen(onFulfill, onReject) {
//如果是 fulfilled 状态,表示要执行 then 的第一个函数
if (status === 'fulfilled') {
onFulfill && onFulfill(value);
status = 'pending';
//如果是 rejected 状态,表示要执行 then 的第二个函数
} else if (status === 'rejected') {
onReject && onReject(value);
status = 'pending';
//如果状态还是 peding,表示 resolve 或 reject 还没执行,那就先把 then 的两个函数存起来,等 resolve 或 reject 的时候再调用
} else {
onResolvedCallback = onFulfill;
onRejectedCallback = onReject;
}
}
//将 then 得到的函数传给 toDoThen
this.then = function(onFulfill, onReject) {
toDoThen(onFulfill, onReject);
};
//执行 fn
fn(resolve, reject);
return this;
}
复制代码
测试一波
var promise = new Promise(function(resolve, reject) {
setTimeout(() => {
resolve('hello');
}, 3000);
});
promise.then(
val => {
console.log('第一次成功', val);
},
val => {
console.log('第一次失败', val);
}
);
复制代码
执行时会打印出 '第一次成功' 和 'hello'
链式 then
如果想要实现以下的代码,让第二个 then 的执行函数是根据第一个 then 返回值的布尔值来确定的。
promise
.then(
val => {
console.log('第一次成功', val);
return 'world';
},
val => {
console.log('第一次失败', val);
return false;
}
)
.then(
val => {
console.log('第二次成功', val);
},
val => {
console.log('第二次失败', val);
}
);
复制代码
这里如果要实现链式 then,那么 then 返回的也必须是一个 Promise 对象,并根据第一个 then 的返回值来确定下一个 then 调用哪个函数。
function Promise(fn) {
//初始 status 为 peding
let status = 'pending';
//存储 then 回调值
let value;
//存储 then 的两个参数
let onResolvedCallback;
let onRejectedCallback;
//设置 fn 的 resolve 函数
function resolve(data) {
//将 status 变成 fulfilled
status = 'fulfilled';
//存储回调函数的值
value = data;
toDoThen(onResolvedCallback, onRejectedCallback);
}
//设置 fn 的 reject 函数
function reject(data) {
//将 status 变成 rejected
status = 'rejected';
//存储回调函数的值
value = data;
toDoThen(onResolvedCallback, onRejectedCallback);
}
//设置 resolve 或 reject 时的执行体
function toDoThen(onFulfill, onReject) {
//如果是 fulfilled 状态,表示要执行 then 的第一个函数
if (status === 'fulfilled') {
onFulfill && onFulfill(value);
status = 'pending';
//如果是 rejected 状态,表示要执行 then 的第二个函数
} else if (status === 'rejected') {
onReject && onReject(value);
status = 'pending';
//如果状态还是 peding,表示 resolve 或 reject 还没执行,那就先把 then 的两个函数存起来,等 resolve 或 reject 的时候再调用
} else {
onResolvedCallback = onFulfill;
onRejectedCallback = onReject;
}
}
this.then = function(onFulfill, onReject) {
return new Promise((resolve, reject) => {
toDoThen(
val => {
let result = onFulfill(val);
//根据第一个 then 的返回值来确定下一个 then 的调用
result ? resolve(result) : reject(result);
},
err => {
let result = onReject(err);
//根据第一个 then 的返回值来确定下一个 then 的调用
result ? resolve(result) : reject(result);
}
);
});
};
//执行 fn
fn(resolve, reject);
return this;
}
复制代码
来执行一下
var promise = new Promise(function(resolve, reject) {
setTimeout(() => {
resolve('hello');
}, 3000);
});
promise
.then(
val => {
console.log('第一次成功', val);
return 'world';
},
val => {
console.log('第一次失败', val);
return false;
}
)
.then(
val => {
console.log('第二次成功', val);
},
val => {
console.log('第二次失败', val);
}
)
复制代码
程序会依次输出 '第一次成功' 'hello' 和 '第二次成功' 'world' 。
到此就实现了一个简易版的 Promise,当然,还有很多地方细节没有考虑到,实现地非常粗糙。