一:目录
- promise介绍与基本使用
- promise API
- promise关键问题
- promise自定义封装
- async与await
二:第 1 章:Promise 的理解和使用
1、概念:
Promise是异步编程的一种解决方案
,比传统的解决方案——回调函数和事件——更合理和更强大。所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。
通俗讲,Promise是一个许诺、承诺
,是对未来事情的承诺,承诺不一定能完成,但是无论是否能完成都会有一个结果。
- Pending 正在做。。。
- Resolved 完成这个承诺
- Rejected 这个承诺没有完成,失败了
Promise 用来预定一个不一定能完成的任务,要么成功,要么失败
在具体的程序中具体的体现,通常用来封装一个异步任务,提供承诺结果
Promise 是异步编程的一种解决方案,主要用来解决回调地狱的问题,可以有效的减少回调嵌套
。真正解决需要配合async/await
2、特点:
(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称Fulfilled)和Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从Pending变为Resolved和从Pending变为Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。
3、缺点:
(1)无法取消Promise,一旦新建它就会立即执行,无法中途取消。和一般的对象不一样,无需调用。
(2)如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
(3)当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
三:Promise的理解和使用
3.1: Promise是什么?
1:理解
抽象表达:
1) Promise 是一门新的技术(ES6 规范)
2)Promise 是 JS 中进行异步编程
的新解决方案
异步编程:
1: fs 文件操作 (fs是node.js下面的一个模块,可以对计算机的磁盘进行读写操作)
2: 数据库操作
3:ajax
4:定时器
## 异步编程
<!-- fs 文件操作 -->
require('fs').readFile('./index.html',(err,data)=>{})
<!-- 数据库操作 -->
<!-- ajax -->
$.get('/server',(data)=>{})
<!-- 定时器 -->
setTimeout(()=>{},2000);
备注:旧方案是单纯使用回调函数
具体表达:
-
从语法上来说: Promise 是一个
构造函数
-
从功能上来说: promise 对象用来封装一个异步操作并可以获取其成功/ 失败的结果值
//promise初体验.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link crossorigin='anonymous' href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css"
rel="stylesheet">
</head>
<body>
<div class="container">
<h2 class="page-header">Promise 初体验</h2>
<button class="btn btn-primary" id="btn">点击抽奖</button>
</div>
<script>
//生成随机数
function rand(m, n) {
return Math.ceil(Math.random() * (n - m + 1)) + m - 1;
}
/**
点击按钮, 1s 后显示是否中奖(30%概率中奖)
若中奖弹出 恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券
若未中奖弹出 再接再厉
*/
//实现方法一:
// 1:获取元素
const btn = document.querySelector('#btn');
// 2:绑定点击事件
btn.addEventListener('click', function () {
setTimeout(() => {
let n = rand(1, 100);
if (n <= 30) {
alert('恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券')
} else {
alert('再接再厉')
}
}, 10000);
//实现方法二:Promise 形式实现
// resolve 解决 函数类型的数据
// reject 拒绝 函数类型的数据
const p = new Promise((resolve, reject) => {
setTimeout(() => {
let n = rand(1, 100);
if (n <= 30) {
//promise的作用:除了封装异步操作之外,还可以获取异常任务当中成功和失败的结果值;可以把n当作结果值,传给resolve,reject
resolve(n); // 将 promise 对象的状态设置为 『成功』
} else {
reject(n); // 将 promise 对象的状态设置为 『失败』
}
}, 1000)
})
console.log(p);
//调用 then 方法:通过then方法指定成功和失败时的回调
// value 值
// reason 理由
//()=>{} 参数一是成功的回调
// ()=>{} 参数二是失败饿回调
p.then((value) => {
alert('恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券, 您的中奖数字为 ' + value);
}, (reason) => {
alert('再接再厉, 您的号码为 ' + reason);
})
})
</script>
</body>
</html>
promise实践练习
//js
// 需求;读取resource下的conten.txt内容
const { rejects } = require('assert');
const fs = require('fs');
// 方法一:回调函数 形式
fs.readFile('./resource/content.txt', (err, data) => {
//如果有错,则抛出错误
if (err) throw err;
// 输出文件内容
console.log(data.toString());
});
// 方法二:promise 形式
let p = new Promise((resolve, reject) => {
fs.readFile('./resource/content.txt', (err, data) => {
//如果出错
if (err) reject(err);
//如果成功
resolve(data);
})
});
// 调用 then
p.then(value => {
console.log(value.toString());
}, reason => {
console.log(reason);
})
//ajax操作的封装.html
//需求:点击按钮,给接口地址发送ajax请求,获取信息
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise 封装 AJAX</title>
<link crossorigin='anonymous' href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<h2 class="page-header">Promise 封装 AJAX 操作</h2>
<button class="btn btn-primary" id="btn">点击发送 AJAX</button>
</div>
<script>
//接口地址 https://api.apiopen.top/getJoke
//获取元素对象
const btn = document.querySelector('#btn');
btn.addEventListener('click', function(){
//创建 Promise
const p = new Promise((resolve, reject) => {
//1.创建对象
const xhr = new XMLHttpRequest();
//2. 初始化
xhr.open('GET', 'https://api.apiopen.top/getJoke');
//3. 发送
xhr.send();
//4. 处理响应结果
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
//判断响应状态码 2xx
if(xhr.status >= 200 && xhr.status < 300){
//控制台输出响应体
resolve(xhr.response);
}else{
//控制台输出响应状态码
reject(xhr.status);
}
}
}
});
//调用then方法
p.then(value=>{
console.log(value);
}, reason=>{
console.warn(reason);
});
});
</script>
</body>
</html>
promise封装练习-fs模块.js
//js
/**
* 封装一个函数 mineReadFile 读取文件内容
* 参数: path 文件路径
* 返回: promise 对象
*/
function mineReadFile(path){
return new Promise((resolve, reject) => {
//读取文件
require('fs').readFile(path, (err, data) =>{
//判断
if(err) reject(err);
//成功
resolve(data);
});
});
}
mineReadFile('./resource/content.txt')
.then(value=>{
//输出文件内容
console.log(value.toString());
}, reason=>{
console.log(reason);
});
node.js的内置方法---util.promisify方法
对于使用promise,我们不需要每个方法都去手动的进行封装,可以借助util.promisify()方法,将原来的回调函数转变成promise的·函数,这样代码使用起来更加方便!
//js
/**
* 封装一个函数 mineReadFile 读取文件内容
* 参数: path 文件路径
* 返回: promise 对象
*/
function mineReadFile(path){
return new Promise((resolve, reject) => {
//读取文件
require('fs').readFile(path, (err, data) =>{
//判断
if(err) reject(err);
//成功
resolve(data);
});
});
}
mineReadFile('./resource/content.txt')
.then(value=>{
//输出文件内容
console.log(value.toString());
}, reason=>{
console.log(reason);
});
//Promise封装AJAX操作.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise封装AJAX操作</title>
</head>
<body>
<script>
/**
* 封装一个函数 sendAJAX 发送 GET AJAX 请求
* 参数 URL
* 返回结果 Promise 对象
*/
function sendAJAX(url){
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.open("GET", url);
xhr.send();
//处理结果
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
//判断成功
if(xhr.status >= 200 && xhr.status < 300){
//成功的结果
resolve(xhr.response);
}else{
reject(xhr.status);
}
}
}
});
}
sendAJAX('https://api.apiopen.top/getJok')
.then(value => {
console.log(value);
}, reason => {
console.warn(reason);
});
</script>
</body>
</html>
2: promise的状态改变
3、Promise中的常用 API 概述
此处列举几个最常用的API的概述,如果想看详细描述的可以继续往下看下方的 Promise方法的具体使用 描述
Ⅰ- Promise 构造函数: Promise (excutor) {}
(1) executor 函数: 执行器 (resolve, reject) => {}
(2) resolve 函数: 内部定义成功时我们调用的函数 value => {}
(3) reject 函数: 内部定义失败时我们调用的函数 reason => {}
说明: executor 会在 Promise 内部立即
同步调用
,异步操作在执行器中执行,换话说Promise支持同步也支持异步操作
Ⅱ-Promise.prototype.then 方法: (onResolved, onRejected) => {}
(1) onResolved 函数: 成功的回调函数 (value) => {}
(2) onRejected 函数: 失败的回调函数 (reason) => {}
说明: 指定用于得到成功 value 的成功回调和用于得到失败 reason 的失败回调 返回一个新的 promise 对象
Ⅲ-Promise.prototype.catch 方法: (onRejected) => {}
(1) onRejected 函数: 失败的回调函数 (reason) => {}
说明: then()的语法糖, 相当于: then(undefined, onRejected)
(2) 异常穿透使用:当运行到最后,没被处理的所有异常错误都会进入这个方法的回调函数中
//html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
let p1 = Promise.resolve(521);
// 如果传入的参数为 非promise类型的对象,则返回的结果为成功promise对象
// 如果传入的参数为promse 对象,则参数的结果决定了 resolve 的结果
let p2 = Promise.resolve(new Promise((resolve, reject) => {
// resolve('ok');
reject('error');
}));
console.log(p2);
// catch() 处理错误的回调函数
p2.catch(reason => {
console.log(reason);
})
</script>
</body>
</html>
Ⅳ-Promise.resolve 方法: (value) => {}
(1) value: 成功的数据或 promise 对象
说明: 返回一个成功/失败的 promise 对象,直接改变promise状态
let p3 = Promise.reject(new Promise((resolve, reject) => { resolve('OK'); })); console.log(p3);
Ⅴ-Promise.reject 方法: (reason) => {}
(1) reason: 失败的原因
说明: 返回一个失败的 promise 对象,直接改变promise状态,
代码示例同上
//html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// let p = Promise.reject(521);
// let p2 = promise.reject('iloveyou');
// 传入什么参数就返回什么参数
let p3 = promise.reject(new promise((resolve, reject) => {
resolve('ok');
}));
console.log(p3);
</script>
</body>
</html>
Ⅵ-Promise.all 方法: (promises) => {}
promises: 包含 n 个 promise 的数组
说明: 返回一个新的 promise, 只有所有的 promise
都成功才成功
, 只要有一 个失败了就直接失败
//html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
let p1 = new Promise((resolve, reject) => {
resolve('ok');
});
// let p2 = Promise.resolve('success');
let p2 = Promise.reject('error');
let p3 = Promise.resolve('oh yeah');
const result = Promise.all([p1, p2, p3]);
console.log(result);
</script>
</body>
</html>
Ⅶ-Promise.race 方法: (promises) => {}
(1) promises: 包含 n 个 promise 的数组
说明: 返回一个新的 promise,
第一个完成
的 promise 的结果状态就是最终的结果状态,如p1延时,开启了异步,内部正常是同步进行,所以
p2>p3>p1
,结果是P2
//html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok');
}, 1000)
})
let p2 = Promise.resolve('success');
let p3 = Promise.resolve('oh yeah');
// 调用
const result = Promise.race([p1, p2, p3]);
console.log(result);
</script>
</body>
</html>
4、Promise的几个关键问题
Ⅰ-如何改变 promise 的状态?
(1) resolve(value): 如果当前是 pending 就会变为 resolved
(2) reject(reason): 如果当前是 pending 就会变为 rejected
(3) 抛出异常: 如果当前是 pending 就会变为 rejected
//html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
let p = new Promise((resolve,reject)=>{
// 1:resolve 函数
resolve('ok'); //pending => fulfilled(resolved)
// 2: reject 函数
reject('error'); //pending => rejected
// 3: 抛出错误
throw '出问题了';
})
</script>
</body>
</html>
Ⅱ-一个 promise 指定多个成功/失败回调函数, 都会调用吗?
这里指定多个回调函数,就是then()方法;
如果我们使用then方法,为一个promise对象去指定多个回调,这些回调是不是都会执行?当promise改变对应状态时都会调用。
//html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
let p = new Promise((resolve, reject) => {
resolve('ok');
});
// 指定回调 1
p.then(value => {
console.log(value);
});
// 指定回调 2
p.then(value => {
alert(value);
})
</script>
</body>
</html>
Ⅲ- 改变 promise 状态和指定回调函数谁先谁后?
是指执行的谁先谁后!
(1) 都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
先指定回调再改变状态(
异步
):先指定回调--> 再改变状态 -->改变状态后才进入异步队列执行回调函数 先改状态再指定回调(
同步
):改变状态 -->指定回调并马上执行
回调(2) 如何先改状态再
指定
回调? -->注意:指定并不是执行 ① 在执行器中直接调用 resolve()/reject() -->即,不使用定时器等方法,执行器内直接同步操作
② 延迟更长时间才调用 then() -->即,在
.then()
这个方法外再包一层例如延时器这种方法(3) 什么时候才能得到数据?
① 如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
② 如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据
(4) 个人理解--结合源码
源码中,promise的状态是通过一个
默认为padding
的变量进行判断,所以当你resolve/reject
延时(异步导致当then加载时,状态还未修改)后,这时直接进行p.then()会发现,目前状态还是进行中
,所以只是这样导致只有同步操作才能成功. 所以promise将传入的
回调函数
拷贝到promise对象实例上,然后在resolve/reject
的执行过程中再进行调用,达到异步的目的 具体代码实现看下方自定义promise
//html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise关键问题 - Promise 改变状态与指定回调的顺序问题</title>
</head>
<body>
<script>
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('OK');
}, 1000);
});
p.then(value => {
console.log(value);
},reason=>{
})
</script>
</body>
</html>
Ⅳ-promise.then()返回的新 promise 的结果状态由什么决定?
(1) 简单表达: 由 then()指定的回调函数执行的结果决定
(2) 详细表达:
① 如果抛出异常, 新 promise 变为 rejected, reason 为抛出的异常
② 如果返回的是非 promise 的任意值, 新 promise 变为 resolved, value 为返回的值
③ 如果返回的是另一个新 promise, 此 promise 的结果就会成为新 promise 的结果
//html
let p = new Promise((resolve, reject) => {
resolve('ok');
});
//执行 then 方法
let result = p.then(value => {
console.log(value);
// 1. 抛出错误 ,变为 rejected
throw '出了问题';
// 2. 返回结果是非 Promise 类型的对象,新 promise 变为 resolved
return 521;
// 3. 返回结果是 Promise 对象,此 promise 的结果就会成为新 promise 的结果
return new Promise((resolve, reject) => {
// resolve('success');
reject('error');
});
}, reason => {
console.warn(reason);
});
//html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise关键问题 - Promise then方法的返回结果特点</title>
</head>
<body>
<script>
let p = new Promise((resolve, reject) => {
resolve('ok');
});
//执行 then 方法
let result = p.then(value => {
// console.log(value);
//1. 抛出错误
// throw '出了问题';
//2. 返回结果是非 Promise 类型的对象
// return 521;
//3. 返回结果是 Promise 对象
// return new Promise((resolve, reject) => {
// // resolve('success');
// reject('error');
// });
}, reason => {
console.warn(reason);
});
console.log(result);
</script>
</body>
</html>
Ⅴ- promise 如何串连多个操作任务?
(1) promise 的 then()返回一个新的 promise, 可以开成 then()的链式调用
(2) 通过 then 的链式调用串连多个同步/异步任务,这样就能用
then()
将多个同步或异步操作串联成一个同步队列<script> let p = new Promise((resolve, reject) => { setTimeout(() => {resolve('OK'); }, 1000); }); p.then(value => {return new Promise((resolve, reject) => { resolve("success"); });}) .then(value => {console.log(value);}) .then(value => { console.log(value);}) </script>
//html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise关键问题 - 如何串联多个任务</title>
</head>
<body>
<script>
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('OK');
}, 1000);
});
p.then(value => {
return new Promise((resolve, reject) => {
resolve("success");
});
}).then(value => {
console.log(value);
}).then(value => {
console.log(value);
})
</script>
</body>
</html>
Ⅵ-promise 异常传透?
- 当使用 promise 的 then 链式调用时, 可以在最后指定失败的回调
- 前面任何操作出了异常, 都会传到最后失败的回调中处理
getJSON('./hong.json') .then(function(posts) { throw new Error('抛出异常') }) .then(res=>console.log(res),e=>console.log('被then的错误回调捕获',e) ) .catch(function(error) { // 处理 getJSON 和 前一个回调函数运行时发生的错误 console.log('错误捕获: ', error); }); //执行结果: 被then的错误回调捕获 Error: 抛出异常 /******************** 利用异常穿****************************************/ getJSON('./hong.json') .then(function(posts) { throw new Error('抛出异常') }) .then(res=>console.log(res) ) //此处差异,不指定 reject 回调,利用异常穿透传到最后 .catch(function(error) { console.log('错误捕获: ', error); }); //执行结果: 错误捕获: Error: 抛出异常注:可以在每个then()的第二个回调函数中进行err处理,也可以利用异常穿透特性,到最后用
catch
去承接统一处理,两者一起用时,前者会生效(因为err已经将其处理,就不会再往下穿透)而走不到后面的catch
//html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise关键问题 - 异常穿透</title>
</head>
<body>
<script>
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('OK');
// reject('Err');
}, 1000);
});
p.then(value => {
// console.log(111);
throw '失败啦!';
}).then(value => {
console.log(222);
}).then(value => {
console.log(333);
}).catch(reason => {
console.warn(reason);
});
</script>
</body>
</html>
Ⅶ- 中断 promise 链?
在
关键问题2
中,可以得知,当promise状态改变时,他的链式调用都会生效,那如果我们有这个一个实际需求:我们有5个then(),但其中有条件判断,如当我符合或者不符合第三个then条件时,要直接中断链式调用,不再走下面的then,该如何?(1) 当使用 promise 的 then 链式调用时, 在中间中断, 不再调用后面的回调函数
(2) 办法: 在回调函数中返回一个
pendding
状态的promise 对象
<script> let p = new Promise((resolve, reject) => {setTimeout(() => { resolve('OK');}, 1000);}); p.then(value => {return new Promise(() => {});})//有且只有这一个方式 .then(value => { console.log(222);}) .then(value => { console.log(333);}) .catch(reason => {console.warn(reason);}); </script>
//html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise关键问题 - 中断 Promise 链条</title>
</head>
<body>
<script>
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('OK');
}, 1000);
});
p.then(value => {
console.log(111);
//有且只有一个方式
return new Promise(() => {});
}).then(value => {
console.log(222);
}).then(value => {
console.log(333);
}).catch(reason => {
console.warn(reason);
});
</script>
</body>
</html>
四、自定义Promise手写
- 下方的
Promise.prototype.then
与Promise.resolve
为什么一个挂载在prototype
而另一个挂载在实例对象上?解:原因是分别为静态方法与实例方法
-->上面的需要new实例化的时候自动继承实例
prototype
上的方法和属性,所以用实例对象.then()
来调用,而下面的Promise.resolve是静态方法,不用new,是可以直接Promise.resolve()调用
Ⅰ-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) {}
//html
//声明构造函数
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) {}
//js
//声明构造函数
function Promise(executor){
//添加属性
this.PromiseState = 'pending';
this.PromiseResult = null;
//保存实例对象的 this 的值
const self = this;// self _this that
//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); }
//js
//声明构造函数
function Promise(executor){
//添加属性
this.PromiseState = 'pending';
this.PromiseResult = null;
//保存实例对象的 this 的值
const self = this;// self _this that
//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;
}
try{
//同步调用『执行器函数』
executor(resolve, reject);
}catch(e){
//修改 promise 对象状态为『失败』
reject(e);
}
}
//添加 then 方法
Promise.prototype.then = function(onResolved, onRejected){
}
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; }
//html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise-封装 | 5 - 状态只能修改一次 </title>
<script src="./promise.js"></script>
</head>
<body>
<script>
let p = new Promise((resolve, reject) => {
reject("error");
resolve('OK');
//抛出异常
// throw "error";
});
console.log(p);
</script>
</body>
</html>
//js
//声明构造函数
function Promise(executor){
//添加属性
this.PromiseState = 'pending';
this.PromiseResult = null;
//保存实例对象的 this 的值
const self = this;// self _this that
//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;
}
try{
//同步调用『执行器函数』
executor(resolve, reject);
}catch(e){
//修改 promise 对象状态为『失败』
reject(e);
}
}
//添加 then 方法
Promise.prototype.then = function(onResolved, onRejected){
}
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);} }
//htmml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise-封装 | 6 - then 方法执行回调 </title>
<script src="./promise.js"></script>
</head>
<body>
<script>
//实例化对象
let p = new Promise((resolve, reject) => {
// resolve('OK');
// reject("Error");
throw "ERROR";
});
p.then(value => {
console.log(value);
}, reason=>{
console.warn(reason);
})
</script>
</body>
</html>
//js
//声明构造函数
function Promise(executor){
//添加属性
this.PromiseState = 'pending';
this.PromiseResult = null;
//保存实例对象的 this 的值
const self = this;// self _this that
//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;
}
try{
//同步调用『执行器函数』
executor(resolve, reject);
}catch(e){
//修改 promise 对象状态为『失败』
reject(e);
}
}
//添加 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 }); } }
//html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise-封装 | 8 - 指定多个回调 </title>
<script src="./promise.js"></script>
</head>
<body>
<script>
//实例化对象
let p = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve('OK');
reject('No');
}, 1000);
});
p.then(value => {
console.log(value);
}, reason=>{
console.warn(reason);
});
p.then(value => {
alert(value);
}, reason=>{
alert(reason);
});
console.log(p);
</script>
</body>
</html>
//js
//声明构造函数
function Promise(executor){
//添加属性
this.PromiseState = 'pending';
this.PromiseResult = null;
//声明属性
this.callbacks = [];
//保存实例对象的 this 的值
const self = this;// self _this that
//resolve 函数
function resolve(data){
//判断状态
if(self.PromiseState !== 'pending') return;
//1. 修改对象的状态 (promiseState)
self.PromiseState = 'fulfilled';// resolved
//2. 设置对象结果值 (promiseResult)
self.PromiseResult = data;
//调用成功的回调函数
self.callbacks.forEach(item => {
item.onResolved(data);
});
}
//reject 函数
function reject(data){
//判断状态
if(self.PromiseState !== 'pending') return;
//1. 修改对象的状态 (promiseState)
self.PromiseState = 'rejected';//
//2. 设置对象结果值 (promiseResult)
self.PromiseResult = data;
//执行失败的回调
self.callbacks.forEach(item => {
item.onRejected(data);
});
}
try{
//同步调用『执行器函数』
executor(resolve, reject);
}catch(e){
//修改 promise 对象状态为『失败』
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'){
//保存回调函数
this.callbacks.push({
onResolved: onResolved,
onRejected: onRejected
});
}
}