b站视频-尚硅谷Web前端Promise从入门到精通-笔记

前言

在继续学习React-ajax、axios之前,先来学习promise
看的是b站尚硅谷李强老师的视频:Promise从入门到自定义

一、Promise视频简介

包含以下内容:

  1. Promise介绍与基本使用
  2. Promise API
  3. Promise关键问题
  4. Promise自定义封装
  5. async与await

二、Promise的介绍

ES6引入的进行异步编程的解决方案,从语法上说它是一个构造函数。
异步编程包括但不限于:文件操作、数据库操作、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读取文件

Node.js—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请求

<script type="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);
            });
        });
    </script>

五、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.promisify是在node.js 8.x版本中新增的一个工具,用于将老式的Error first callback转换为Promise对象,让老项目改造变得更为轻松。
关于util.promisify

//  引入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 失败

Promise 对象的值:实例对象中的另一个属性 『PromiseResult』
保存着异步任务『成功/失败』的结果

  • resolve
  • reject

九、Promise工作流程

在这里插入图片描述

十、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.改变状态与指定回调的顺序问题(不理解)

b站视频-p20
(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.串联多个任务

b站视频-p22
(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函数

b站视频p43

  • 函数的返回值为 promise 对象,promise 对象的结果由 async 函数执行的返回值决定
    • 如果返回值是一个非Promise类型的数据 fulfilled 成功的结果值即为return值
    • 如果返回的是一个Promise对象 与该promise返回值一致
    • 抛出异常 rejected–结果值即为抛出的异常值

十四、await表达式

  1. await 右侧的表达式一般为 promise 对象, 但也可以是其它的值
  2. 如果表达式是 promise 对象, await 返回的是 promise 成功的值
  3. 如果表达式是其它值, 直接将此值作为 await 的返回值

注:

  1. await 必须写在 async 函数中, 但 async 函数中可以没有 await
  2. 如果 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结合实践

/**
 * resource  1.html  2.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);
        });

写在后面

十二-十六开始看不懂了,没怎么看,以后有机会再慢慢看吧。
接下来去学习axios-从入门到源码分析

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值