目录
- 前言
- 一、Promise视频简介
- 二、Promise的介绍
- 三、Promise的初体验
- 四、Promise实践练习
-
- 1. fs读取文件
- 2. AJAX请求
- 五、Promise封装fs读取文件操作
- 六、util.promisify方法进行promise风格转化
- 七、Promise封装AJAX请求
- 八、Promise对象状态属性介绍
- 九、Promise工作流程 ![在这里插入图片描述](https://img-blog.csdnimg.cn/90b7472b49fe46b19bee607ab6313d94.png)
- 十、Promise的API
-
- 1.构造函数-then-catch
- 2.Promise.resolve()方法
- 3.Promise.reject()方法
- 4.Promise.all()方法
- 5.Promise.race()方法
- 十一、Promise关键问题
-
- 1.如何修改对象的状态
- 2.能否执行多个回调
- ==3.改变状态与指定回调的顺序问题==(不理解)
- 4.then方法返回结果由什么决定
- 5.串联多个任务
- 6.异常穿透
- 7.如何中断promise链
- 十二、Promise自定义封装(又称手写Promise)
-
- 1.初始结构搭建
- 2.resolve与reject结构搭建
- 3.resolve与reject代码实现
- 4.throw抛出异常改变状态
- 5.Promise对象状态只能修改一次
- 6.then方法执行回调
- ==7.异步任务回调的执行==(不理解)
- 8. 指定多个回调的实现
- ==9.同步修改状态then方法结果返回==(不理解)
- 10.异步修改状态then方法结果返回
- 11.then方法完善与优化
- 12.catch方法-异常穿透与值传递
- 13.resolve方法封装
- 14.reject方法封装
- 15.all方法封装
- 16.race方法封装
- 17.then方法回调的异步执行
- 18.class版本的实现
- 十三、async函数
- 十四、await表达式
- 十五、async与await结合实践
- 十六、async与await结合发送AJAX请求
- 写在后面
前言 在继续学习React-ajax、axios之前,先来学习promise
看的是b站尚硅谷李强老师的视频:Promise从入门到自定义
一、Promise视频简介 包含以下内容:
- Promise介绍与基本使用
- Promise API
- Promise关键问题
- Promise自定义封装
- async与await
异步编程包括但不限于:文件操作、数据库操作、AJAX、定时器
为什么要用Promise?
支持链式调用,可以解决回调地狱问题,如下图,回调地狱不便于阅读和异常处理。
文章图片
三、Promise的初体验 实现:
点击按钮, 1s 后显示是否中奖(30%概率中奖)
若中奖弹出 恭喜您中奖
若未中奖弹出 谢谢参与
//Promise是构造函数,所以可以进行对象的实例化
// resolve和reject都是函数类型的数据
const p=new Promise((resolve,reject)=>{
setTimeout(()=>{
// 30%1 2 ... 30
// 获取从1-100的一个随机数
let n=rand(1,100)
// 判断
if(n<=30){
resolve(n);
// 将 promise 对象的状态设置为 『成功』
}else{
reject(n);
// 将 promise 对象的状态设置为 『失败』
}
},1000);
});
// 调用then方法
// 成功就调用第一个回调函数,失败调用第二个回调
p.then((value)=>{
alert('恭喜您中奖,您的中奖号码为'+value);
},(reason)=>{
alert('谢谢参与,您的号码为'+reason);
});
四、Promise实践练习 1. fs读取文件
let p=new Promise((resolve, reject)=>{
fs.readFile('./resource/content.txt',(err,data)=>{
// 如果出错
if(err) reject(err);
// 如果成功
resolve(data);
});
});
p.then(value=>{
console.log(value.toString());
},reason=>{
console.log(reason);
})
文章图片
2. AJAX请求
="text/javascript">
//接口地址 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){
// 判断响应状态码
if(xhr.status>=200&&xhr.status<300){
// 控制台输出响应体
// console.log(xhr.response);
resolve(xhr.response);
}else{
// 控制台输出响应体
// console.log(xhr.status);
reject(xhr.status);
}
}
}
});
p.then(value=>{
console.log(value);
},reason=>{
console.warn(reason);
});
});
五、Promise封装fs读取文件操作 封装一个函数 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);
});
六、util.promisify方法进行promise风格转化
//引入util模块
const util=require('util');
// 引入fs模块
const fs=require('fs');
//返回一个新的函数
let mineReadFile=util.promisify(fs.readFile);
mineReadFile('./resource/content.txt').then(value=>{
console.log(value.toString());
});
七、Promise封装AJAX请求 封装一个函数 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);
});
八、Promise对象状态属性介绍 promise的状态:实例对象中的一个属性 『PromiseState』
- pending 未决定的
- resolved / fullfilled 成功
- rejected 失败
保存着异步任务『成功/失败』的结果
- resolve
- reject
文章图片
十、Promise的API 1.构造函数-then-catch
文章图片
let p=new Promise((resolve,reject)=>{
//同步调用先输出111 再输出222
// console.log('111');
// 修改promise对象的状态
reject('error');
});
// console.log('222');
// 执行catch方法(catch只能指定失败的回调函数)
p.catch(reason=>{
console.log(reason);
});
2.Promise.resolve()方法 该方法较特殊,相较于then与catch,它属于Promise这个函数对象,并不属于实例对象。
作用:快速得到一个promise对象
- 如果传入的参数为 非Promise类型的对象, 则返回的结果为成功promise对象
- 如果传入的参数为 Promise 对象, 则参数的结果决定了 resolve 的结果
let p1 = Promise.resolve(521);
let p2 = Promise.resolve(new Promise((resolve, reject) => {
// resolve('OK');
reject('Error');
}));
// console.log(p2);
p2.catch(reason => {
console.log(reason);
})
3.Promise.reject()方法 作用:快速返回一个失败的promise对象。(无论传入什么,返回的都是失败的Promise)
// let p = Promise.reject(521);
// let p2 = Promise.reject('iloveyou');
let p3 = Promise.reject(new Promise((resolve, reject) => {
resolve('OK');
}));
console.log(p3);
4.Promise.all()方法 (promises) => {}
promises:包含 n 个 promise 的数组
注:返回一个新的 promise, 只有所有的 promise 都成功才成功, 只要有一个失败了就
直接失败
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);
5.Promise.race()方法 (promises) => {}
promises:包含 n 个 promise 的数组
注:返回一个新的 promise, 第一个完成的 promise 的结果状态就是最终的结果状态
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);
十一、Promise关键问题 1.如何修改对象的状态
let p = new Promise((resolve, reject) => {
//1. resolve 函数
// resolve('ok');
// pending=> fulfilled (resolved)
//2. reject 函数
// reject("error");
// pending=>rejected
//3. 抛出错误
// throw '出问题了';
});
console.log(p);
2.能否执行多个回调 当promise状态改变为对应状态时都会调用
let p = new Promise((resolve, reject) => {
// resolve('OK');
});
///指定回调 - 1
p.then(value => {
console.log(value);
});
//指定回调 - 2
p.then(value => {
alert(value);
});
3.改变状态与指定回调的顺序问题(不理解) (1) 都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
(2) 如何先改状态再指定回调? ① 在执行器中直接调用 resolve()/reject()
② 延迟更长时间才调用 then()
(3) 什么时候才能得到数据? ① 如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
② 如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('OK');
}, 1000);
});
p.then(value => {
console.log(value);
},reason=>{})
4.then方法返回结果由什么决定 由 then()指定的回调函数执行的结果决定
① 如果抛出异常, 新 promise 变为 rejected, reason 为抛出的异常
② 如果返回的是非 promise 的任意值, 新 promise 变为 resolved, value 为返回的值
③ 如果返回的是另一个新 promise, 此 promise 的结果就会成为新 promise 的结果
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);
5.串联多个任务 (1) promise 的 then()返回一个新的 promise, 可以开成 then()的链式调用
(2) 通过 then 的链式调用串连多个同步/异步任务
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);
// undefined
})
6.异常穿透 (1) 当使用 promise 的 then 链式调用时, 可以在最后指定失败的回调,
(2) 前面任何操作出了异常, 都会传到最后失败的回调中处理
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);
});
7.如何中断promise链 (1) 当使用 promise 的 then 链式调用时, 在中间中断, 不再调用后面的回调函数
(2) 办法: 在回调函数中返回一个 pendding 状态的 promise 对象
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);
});
十二、Promise自定义封装(又称手写Promise) 1.初始结构搭建 2.resolve与reject结构搭建 3.resolve与reject代码实现 4.throw抛出异常改变状态 5.Promise对象状态只能修改一次 6.then方法执行回调 7.异步任务回调的执行(不理解) 8. 指定多个回调的实现 9.同步修改状态then方法结果返回(不理解) 10.异步修改状态then方法结果返回 11.then方法完善与优化 12.catch方法-异常穿透与值传递 13.resolve方法封装 14.reject方法封装 15.all方法封装 16.race方法封装 17.then方法回调的异步执行 18.class版本的实现 十三、async函数
- 函数的返回值为 promise 对象
- promise 对象的结果由 async 函数执行的返回值决定
- await 右侧的表达式一般为 promise 对象, 但也可以是其它的值
- 如果表达式是 promise 对象, await 返回的是 promise 成功的值
- 如果表达式是其它值, 直接将此值作为 await 的返回值
- await 必须写在 async 函数中, 但 async 函数中可以没有 await
- 如果 await 的 promise 失败了, 就会抛出异常, 需要通过 try…catch 捕获处理
async function main(){
let p = new Promise((resolve, reject) => {
// resolve('OK');
reject('Error');
})
//1. 右侧为promise的情况
// let res = await p;
//2. 右侧为其他类型的数据
// let res2 = await 20;
//3. 如果promise是失败的状态
try{
let res3 = await p;
}catch(e){
console.log(e);
}
}main();
十五、async与await结合实践
/**
* resource1.html2.html 3.html 文件内容
*/const fs = require('fs');
const util = require('util');
const mineReadFile = util.promisify(fs.readFile);
//回调函数的方式
// fs.readFile('./resource/1.html', (err, data1) => {
//if(err) throw err;
//fs.readFile('./resource/2.html', (err, data2) => {
//if(err) throw err;
//fs.readFile('./resource/3.html', (err, data3) => {
//if(err) throw err;
//console.log(data1 + data2 + data3);
//});
//});
// });
//async 与 await
async function main(){
try{
//读取第一个文件的内容
let data1 = await mineReadFile('./resource/1x.html');
let data2 = await mineReadFile('./resource/2.html');
let data3 = await mineReadFile('./resource/3.html');
console.log(data1 + data2 + data3);
}catch(e){
console.log(e.code);
}
}main();
十六、async与await结合发送AJAX请求
//axios
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);
}
}
}
});
}//段子接口地址 https://api.apiopen.top/getJoke
let btn = document.querySelector('#btn');
btn.addEventListener('click',async function(){
//获取段子信息
let duanzi = await sendAJAX('https://api.apiopen.top/getJoke');
console.log(duanzi);
});
写在后面 【前端|b站视频-尚硅谷Web前端Promise从入门到精通-笔记】十二-十六开始看不懂了,没怎么看,以后有机会再慢慢看吧。
接下来去学习axios
推荐阅读
- 【华为联机对战】下载运行华为官方Unity示例代码,提示鉴权失败并返回错误码100114
- IT|怎么都在叫做软件测试(我做软件测试工作的两大乐趣)
- C++笔记|c++入门(二)函数重载 --- c和c++中相互调用对方的静态库
- c++|唠唠C++入门那些事
- C++|C++快速入门(上)
- 前端|Element-UI 表单校验
- javaScript|JS中ES6的模块化
- vue.js|ES6模块化开发
- ES6新特性|ES6新特性-模块化(import/export)