自定义Promise之构造函数最简单实现


理解

HTML 页面内的异步任务(如:settimeout)用 Promise 包裹“托管”起来,不影响后面代码执行(js 非阻塞);HTML 页面内调用 then 或者 catch 方法,其实是将成功和失败的回调函数传递到 Promise.js 中;Promise.js 存储 HTML 页面传递过来的回调函数,当页面内的异步任务结束后,调用 resolve 或 rejecte 方法,resolve 或 reject 方法执行事先存储的回调函数。

过程

  • HTML 页面中,Promise 用来包裹异步回调,then 方法是同步执行
    • then 方法的调用用来存储成功和失败的回调函数
    • Promise 内包裹的异步回调中调用 resolve 或 rejecte 方法
  • Promise.js 模块,resolve 或 rejecte 方法调用
    • resolve 或 rejecte 方法改变状态
    • resolve 或 rejecte 方法执行一开始 HTML 同步执行时候传递到 Promise 模块存储起来的回调函数

实现

JavaScript 部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/**
* 自定义Promise函数 模块
* ES5中模块定义方法:匿名函数自调用(或者自调用函数表达式或者函数表达式自调用)即IIFE
*/
(function (window) {
/**
* Promise构造函数
* excutor:执行器函数(同步执行)
*/
function Promise(excutor) {
//1、构造函数实现
//1.7构造函数测试——将当前promise对象保存起来,存储self
const self = this;

//1.3思考promise实例对象有怎样的属性?
//1.3.1存储状态的属性(给promise对象指定status属性,初始值为pending)
self.status = "pending";
//1.3.2存储数据结果值的属性(给给promise对象指定一个用于存储结果数据的属性)
self.data = undefined;
//1.3.3存储回调函数,每个元素的结构:{onResolved(){},onRejected(){}}
self.callbacks = [];

function resolve(value) {
//1.2定义resolve和reject两个方法
//1.5 还有一个问题,不能反复的resolve,思考如果当前状态不是pending,直接结束,如何限制状态只改一次
if (self.status !== "pending") {
return;
}

//1.4思考执行resolve和reject方法需要做什么?
//1.4.1将状态改为resolved
self.status = "resolved";
//1.4.2保存value数据
self.data = value;

/**
* 1.4.3调用resolve的时候可能已经指定了回调函数,如果有待执行的callback函数,异步执行回调,放入回调队列
* 立即异步执行回调函数onResolved
* callbackObj为包含两个回调函数的对象
* 回调函数放入到队列中,使用settimeout函数模拟
*/
if (self.callbacks.length > 0) {
// callbackObj.onResolved();//这样还是同步,未放入队列中
setTimeout(() => {
//模拟异步回调,放入队列中,执行所有成功回调
self.callbacks.forEach((callbacksObj) => {
callbacksObj.onResolved(value); //调用成功的回调,怎么能不传参数呢
});
});
}
}

function reject(reason) {
//1.3两函数形参value和reason
if (self.status !== "pending") {
return;
}
self.status = "rejected";
self.data = reason;
if (self.callbacks.length > 0) {
setTimeout(() => {
self.callbacks.forEach((callbacksObj) => {
callbacksObj.onRejected(reason);
});
});
}
}

//1.6既没调resolve也没调rejecte,执行器抛出异常,promise状态变为失败,有抛出异常就有捕获异常
try {
excutor(resolve, reject); //1.1立即同步执行执行器,需要传入两参数
} catch (error) {
//如果执行器抛出异常,promise对象变为rejected
reject(error);
}
}
/**
* Promise原型对象的then()
* 指定成功和失败的回调函数
* 返回一个新的Promise对象
*/
Promise.prototype.then = function (onResolved, onRejected) {
/**
* 最简单实现
* 假设当前状态还是pending状态,不能执行回调函数,
* 状态不由.then来改,只能把两个回调函数存储起来
*/
const self = this;
self.callbacks.push({
onResolved,
onRejected,
});
};

/**
* Promise原型对象的catch()
* 指定失败的回调函数
* 返回一个新的Promise对象
*/
Promise.prototype.catch = function (onRejected) {};
/**
* Promise函数对象方法 resolve()
* 返回一个指定结果的成功的promise
*/
Promise.resolve = function (value) {};
/**
* Promise函数对象方法reject()
* 返回一个指定reason的失败的promise
*/
Promise.reject = function (reason) {};
/**
* Promise函数对象的all方法
* 返回一个promise,只有当所有promise都成功时才成功,否则只要有一个失败的就失败
*/
Promise.all = function (promises) {};
/**
* Promise函数对象的race方法
* 返回一个promise,其结果由第一个完成的promise决定
*/
Promise.race = function (promises) {};

//向外暴露Promise函数
window.Promise = Promise;
})(window);

HTML 部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>自定义Promise</title>
</head>

<body>
<ol>
<li>1、自定义Promise——Promise整体框架</li>
<li>2、自定义Promise——Promise构造函数实现</li>
</ol>
<script src="./lib/Promise.js"></script>
<script>
const p = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve(1);//value//1.测试成功
reject(2);//reason//2测试失败
//下面log语句先执行,后面then方法里的回调后执行才验证时异步执行
console.log('reject改变状态');//测试是同步还是异步???
}, 100);
});
p.then(value => {
console.log('onResolved()1', value);
}, reason => {
console.log('onReject()1', reason);
});
p.then(value => {
console.log('onResolved()2', value);
}, reason => {
console.log('onReject()2', reason);
});
</script>
</body>

</html>

文章作者: AlfaLee
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 AlfaLee !
  目录