《尚硅谷Promise教程(promise前端进阶必学)》学习笔记
简单理解
HTML 页面内的异步任务(如:settimeout)用Promise包裹“托管”起来,不影响后面代码执行(js非阻塞);HTML页面内调用then或者catch方法,其实是将成功和失败的回调函数传递到Promise.js中;Promise.js存储HTML页面传递过来的回调函数,当页面内的异步任务结束后,调用 resolve 或 rejecte 方法,resolve 或 reject 方法执行事先存储的回调函数。
大致过程
- HTML 页面中,Promise 用来包裹异步回调,then 方法是同步执行
- then 方法的调用传入成功和失败的回调函数,用以Promise模块存储;
- Promise 内包裹的异步回调中调用 resolve 或 rejecte 方法
- Promise.js 模块,resolve 或 rejecte 方法调用
- resolve 或 rejecte 方法改变状态
- resolve 或 rejecte 方法执行一开始 HTML 同步执行时候传递到Promise模块存储起来的回调函数
具体实现
JavaScript 部分
/**
* 自定义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 部分
<!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>