理解
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>
|