目录
Ⅰ-Promise的实例方法实现
1 - 初始结构搭建
html引入,该章节后续html大部分重复 除非必要,否则不再放上来
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise-封装 | 1 - 初始结构搭建</title>
<script src="./promise.js"></script>
</head>
<body>
<script>
let p = new Promise((resolve, reject) => {
resolve('OK');
});
p.then(value => {
console.log(value);
}, reason=>{
console.warn(reason);
})
</script>
</body>
</html>
promise.js -->使用原生写法,最后会改为class写法
function Promise(executor){}
//添加 then 方法
Promise.prototype.then = function(onResolved, onRejected){}
2 - resolve 与 reject构建与基础实现
- 使用
const self = this;
保存this执行,使function中可以取得当前实例ps:可以不使用该方法保存,但是下方function需要
改为箭头函数
,否则function默认指向是window
之后代码默认使用
self
保存this,箭头函数方式将在最后改为class写法时使用
- 默认设置
PromiseState = 'pending'以及 PromiseResult = null
,这就是promise状态基础
//声明构造函数
function Promise(executor) {
//添加属性
this.PromiseState = 'pending';
this.PromiseResult = null;
//保存实例对象的 this 的值
/* 此处可以不写,但是下面function方法需要改为箭头函数,否则function默认指向是window */
const self = this;
//resolve 函数
function resolve(data) {--------------------------------------------
//1. 修改对象的状态 (promiseState)
self.PromiseState = 'fulfilled'; // resolved
//2. 设置对象结果值 (promiseResult)
self.PromiseResult = data;
}
//reject 函数
function reject(data) {----------------------------------------------
//1. 修改对象的状态 (promiseState)
self.PromiseState = 'rejected'; //
//2. 设置对象结果值 (promiseResult)
self.PromiseResult = data;
}
//同步调用『执行器函数』
executor(resolve, reject);
}
//添加 then 方法
Promise.prototype.then = function (onResolved, onRejected) {}
3 - throw 抛出异常改变状态
- 在2的基础上进行修改:将执行器放入
try-catch()
中- 在catch中使用
reject()
修改 promise 对象状态为『失败
』
try {
//同步调用『执行器函数』
executor(resolve, reject);
} catch (e) {
//修改 promise 对象状态为『失败』
reject(e);
}
4 - 状态只能修改一次
基于2 3代码中resolve和reject方法进修改
在成功与失败函数中添加判断
if(self.PromiseState !== 'pending') return;
,如果进入函数时状态不为pending
直接退出,这样就能做到状态只能从pending
改至其他状态且做到只能改一次
html调用--------------------------------------------------------
let p = new Promise((resolve, reject) => {
reject("error");
resolve('OK');
//抛出异常
// throw "error";
});
console.log(p);
promise.js修改--------------------------------------------------------
//resolve 函数
function resolve(data){
//判断状态
if(self.PromiseState !== 'pending') return;
//1. 修改对象的状态 (promiseState)
self.PromiseState = 'fulfilled';// resolved
//2. 设置对象结果值 (promiseResult)
self.PromiseResult = data;
}
//reject 函数
function reject(data){
//判断状态
if(self.PromiseState !== 'pending') return;
//1. 修改对象的状态 (promiseState)
self.PromiseState = 'rejected';//
//2. 设置对象结果值 (promiseResult)
self.PromiseResult = data;
}
5 - then 方法执行回调基础实现
- 修改
Promise.prototype.then
方法- 传入
then(成功回调,失败回调)
,当调用then后,会判断当前this.PromiseState
的状态,当其为成功时调用成功回调
,失败时调用失败回调
html调用------------------------------------------------------------
let p = new Promise((resolve, reject) => {
// resolve('OK');// reject("Error");
throw "ERROR";
});
p.then(
value => {console.log(value); },
reason => {console.warn(reason);}
)
promise.js修改与实现-----------------------------------------------------
//添加 then 方法
Promise.prototype.then = function (onResolved, onRejected) {
//调用回调函数 PromiseState
if (this.PromiseState === 'fulfilled') {onResolved(this.PromiseResult);}
if (this.PromiseState === 'rejected') {onRejected(this.PromiseResult);}
}
6 - 异步任务 then 方法实现
此处对于5有四处修改,下面上
js代码
当我运行
异步代码
后,我的执行器内部代码还未返回(因为用了定时器,里面的代码进入了异步队列),所以当我下面的.then()运行时:我的p
为pending
状态,所以根本不会执行resolve与reject方法解:添加判断
pending
状态,将当前回调函数保存到实例对象(存到实例上是为了更方便)中,这样后续改变状态时候才调用得到
- 为什么要将回调保存到实例上而不是直接调用?
理由
:因为我的回调函数需要在我的promise状态改变后(成功或者失败),再根据状态选择运行哪个函数 所以当你调用then()
时却检测到状态为pending
,说明这时候的promise在异步队列 不能直接运行成功或者失败函数
解决
:因为resolve与reject
方法与then()
不在同一个作用域中,并不能共享then(成功回调,失败回调)
的参数,所以在判断状态为pending
时将回调保存到实例对象上.然后将回调函数的调用放在resolve()与reject()
中这样当我代码运行到异步队列的
resolve()或reject()
时,就可以在这个函数中运行回调函数,实现异步then
- 此处的then
仍有瑕疵
,需要继续完善
html调用------------------------------------------------------------
//实例化对象
let p = new Promise((resolve, reject) => {
setTimeout(() => {reject("error"); /* resolve('OK');*/}, 1000);
});
p.then(value => {console.log(value);},reason => { console.warn(reason);});
console.log(p);
promise.js修改与实现-----------------------------------------------------
//声明构造函数
function Promise(executor) {
this.PromiseState = 'pending'; this.PromiseResult = null;
// 声明属性
this.callback = {}; -----------新添加1
const self = this;
//resolve 函数
function resolve(data) {
//判断状态
if (self.PromiseState !== 'pending') return;
self.PromiseState = 'fulfilled'; self.PromiseResult = data;
//调用成功的回调函数 加判断的原因是防止无回调报错
if (self.callback.onResolved) { self.callback.onResolved(data); } ------------新添加2 最重要
}
//reject 函数
function reject(data) {
if (self.PromiseState !== 'pending') return;
self.PromiseState = 'rejected'; self.PromiseResult = data;
//执行回调
if (self.callback.onResolved) { self.callback.onResolved(data);} ------------新添加3
}
try {executor(resolve, reject);} catch (e) {reject(e);}
}
//添加 then 方法
Promise.prototype.then = function (onResolved, onRejected) {
//调用回调函数 PromiseState
if (this.PromiseState === 'fulfilled') {onResolved(this.PromiseResult);}
if (this.PromiseState === 'rejected') { onRejected(this.PromiseResult);}
//判断 pending 状态
if (this.PromiseState === 'pending') { ------------新添加4
//保存回调函数
this.callback = {
onResolved: onResolved,
onRejected: onRejected
}
}
}
7 - 指定多个回调
基于6代码进行修改 只展示修改部分代码
6
中保存回调函数的方式有BUG,如果我有多个.then()
,后面加载的回调函数会覆盖之前的回调函数,导致最后回调函数有且只有
最后一个解:使用
数组
的方式进行存储回调函数,调用时也是用数组循环取出
- 此处的then
仍有瑕疵
,需要继续完善
html调用------------------------------------------------------------
//实例化对象
let p = new Promise((resolve, reject) => {setTimeout(() => {reject('No');}, 1000);});
p.then(value => { console.log(value);}, reason=>{console.warn(reason);});
p.then(value => { alert(value);}, reason=>{ alert(reason);});
console.log(p);
promise.js修改与实现-----------------------------------------------------
Promise.prototype.then = function (onResolved, onRejected) {
//resolve 函数
function resolve(data){
.....
//调用成功的回调函数
// if (self.callback.onResolved) { self.callback.onResolved(data); }
self.callbacks.forEach(item => { --------修改1
item.onResolved(data);
});
}
//reject 函数
function reject(data){
......
//执行失败的回调
// if (self.callback.onResolved) { self.callback.onResolved(data);}
self.callbacks.forEach(item => { ------修改2
item.onRejected(data);
});
}
//添加 then 方法
Promise.prototype.then = function(onResolved, onRejected){
........
//判断 pending 状态
if(this.PromiseState === 'pending'){
//保存回调函数
// this.callback = { onResolved: onResolved, onRejected: onRejected }
this.callbacks.push({ --------修改3
onResolved: onResolved,
onRejected: onRejected
});
}
}
8 - 同步任务 then 返回结果
- 在之前的then运行结果中得知,我们使用 [ then ] 后的返回结果是其回调函数的返回结果,而我们需要的返回结果是一个新的promise对象
解:所以我们在then中
return new Promise()
,使其得到的是一个新的promise对象
- 在为
解决问题1
后产生一个新问题:新的promise对象因为没有用rejerect与resolve
方法,导致返回的状态一直是pending
解:在新的promise中判断
运行回调函数
后的返回值是什么,然后根据其不同类型给其赋予不同状态 Ⅰ-
if(result instanceof Promise)
:返回值一个新的②promise对象(因为是新的promise的回调函数返回值,称②promise对象
),在返回值(因为是promise对象)的.then()
回调函数中使用rejerect与resolve方法,将其自身的状态
赋予外层的promise, 即 回调函数中的promise 赋值 给then返回值 , 所以
最终返回状态==回调函数中的新promise状态
Ⅱ-如果返回值是一个
非promise
对象,返回状态设置为成功 Ⅲ-如果返回值是一个异常,返回状态设置为失败
html调用------------------------------------------------------------
//实例化对象
let p = new Promise((resolve, reject) => {resolve('OK');});
//执行 then 方法
const res = p.then(
value => { throw "FAIL";},
reason => { console.warn(reason);});
console.log(res);
promise.js修改与实现-----------------------------------------------------
//添加 then 方法
Promise.prototype.then = function(onResolved, onRejected){
return new Promise((resolve, reject) => {
//调用回调函数 PromiseState
// if(this.PromiseState === 'fulfilled'){ onResolved(this.PromiseResult);} 未修改时代码
if(this.PromiseState === 'fulfilled'){ -------修改1
try{
//获取回调函数的执行结果
let result = onResolved(this.PromiseResult);
//判断
if(result instanceof Promise){//如果是 Promise 类型的对象,我就将下一个promise结果赋予外层
result.then(v => { resolve(v); },r=>{reject(r);})
}else{resolve(result);} //如果返回的不是promise对象,都将其赋予成功状态
}catch(e){
rejerect(e); //如果出错了,则返回失败状态
}
}
if(this.PromiseState === 'rejected'){ onRejected(this.PromiseResult);}------此部分修改与修改1一样
//判断 pending 状态
if(this.PromiseState === 'pending'){
this.callbacks.push({ onResolved: onResolved, onRejected: onRejected});
}
})
}
9 - 异步任务 then 返回结果
异步任务是修改
if(this.PromiseState === 'pending')
后面的值,原因参考6
,下面代码只举例这部分修改因为我们需要增加then状态修改,所以在我们保存回调函数这一步我们可以对于回调函数进行
加工
,添加判断其回调函数的返回值
的代码块再存入实例的回调函数中Ⅰ-声明一个新的函数:其内部功能->先运行
onResolved回调函数
,再将其返回值取出,进行判断其返回值(这个过程同8
)Ⅱ-加工后存入实例回调函数数组,之后在
resolve与reject
方法中调用即可(同6
)
html调用------------------------------------------------------------
//实例化对象
let p = new Promise((resolve, reject) => {
setTimeout(() => {reject("Error");}, 1000)}); // resolve('OK');
//执行 then 方法
const res = p.then(value => {
// return 'oh Yeah'; //如果有返回,根据其返回值得到相应的状态:字符串为成功,抛出为错误
throw 'error';
}, reason => {
console.warn(reason, "xx"); //如果只是打印没返回,则实际上时返回一个undefined,
//在我们封装js中,undefined会判定为非promise对象,所以状态为成功,结果为undefined
return "sss" // throw 'error';
});
console.log(res);
promise.js修改与实现-----------------------------------------------------
//判断 pending 状态
if (this.PromiseState === 'pending') {
//保存回调函数
this.callbacks.push({
onResolved: function () {
try {
//执行成功回调函数
let result = onResolved(self.PromiseResult);
//判断 其结果
if (result instanceof Promise) {
result.then(
v => { resolve(v);},
r => {reject(r);}
)
} else {resolve(result);}
} catch (e) {reject(e);}
},
onRejected: function () {
try {
//执行成功回调函数
let result = onRejected(self.PromiseResult);
//判断
if (result instanceof Promise) {
result.then(
v => {resolve(v); },
r => {reject(r);}
)
} else {resolve(result);}
} catch (e) { reject(e); }
}
});
}
10- then方法代码优化
- 在8、9、10中可以看出,其判断与改变返回结果状态的代码块是基本重复的,所以可以将其抽出
//添加 then 方法
Promise.prototype.then = function (onResolved, onRejected) {
const self = this;
return new Promise((resolve, reject) => {
封装函数----------------------------------------------------------------------------
function callback(type) {
try {
//获取回调函数的执行结果
let result = type(self.PromiseResult);
//判断
if (result instanceof Promise) {
//如果是 Promise 类型的对象
result.then(v => {
resolve(v);
}, r => {
reject(r);
})
} else {
//结果的对象状态为『成功』
resolve(result);
}
} catch (e) {
reject(e);
}
}
-----------------------------------------------------------------------------------
//调用回调函数 PromiseState
if (this.PromiseState === 'fulfilled') {
callback(onResolved);
}
if (this.PromiseState === 'rejected') {
callback(onRejected);
}
//判断 pending 状态
if (this.PromiseState === 'pending') {
//保存回调函数
this.callbacks.push({
onResolved: function () {
callback(onResolved);
},
onRejected: function () {
callback(onRejected);
}
});
}
})
}
11 - catch 方法与异常穿透与值传递
异常穿透:添加
catch 方法
,并且需要进行回调函数为undefined的
处理当我
then()
中只传一个回调或者不传回调函数时,运行代码会报错,因为运行时调用的回调函数是undefined
解:进行回调函数判断,当其为空时,基于默认回调函数内容:
直接往外抛出
这样下方的then() or catch()
就可以承接到异常或者值
html调用------------------------------------------------------------
//实例化对象
let p = new Promise((resolve, reject) => {
setTimeout(() => {resolve('OK'); }, 1000);
});
//值传递
p.then()
.then(value => {console.log(222);})
.then(value => {console.log(333);})
.catch(reason => {console.warn(reason);});
promise.js修改与实现-----------------------------------------------------
//添加 then 方法
Promise.prototype.then = function (onResolved, onRejected) {
... -----------修改1
if (typeof onRejected !== 'function') {onRejected = reason => { throw reason;}}
if (typeof onResolved !== 'function') { onResolved = value => value;}
....
}
//添加 catch 方法
Promise.prototype.catch = function(onRejected){ ---------------异常穿透 修改2
return this.then(undefined, onRejected);