• JS-11-es6常用知识-Promise(6K字超级详解!!)


    文章目录

    1 回调地狱

    2 Promise函数基本用法

    3 Promise函数实现多层回调

     4 Promise传参

    5 Promise 错误处理

    5.1 两种错误处理方式

    5.2 catch捕获错误

    5.3 多层异步种使用catch

    6 使用 Promise 的优势


    1 回调地狱

    1)为什么要有promise?

       解决(回调地狱)的问题 

    2)什么是回调?

        回调(Callback)是一种编程模式,其中一段可执行的代码(即回调函数)作为参数传递给另一个函数(即主函数),并在需要时由主函数执行。这种机制允许主函数在特定事件或条件满足时,调用并执行之前注册的回调函数。

    1. function greet(name, callback) {
    2. console.log(`Hello, ${name}!`);
    3. callback(); // 调用回调函数
    4. }
    5. function sayGoodbye() {
    6. console.log('Goodbye!');
    7. }
    8. greet('Alice', sayGoodbye); // 输出 "Hello, Alice!" 和 "Goodbye!"

         在这个示例中,greet函数接受一个name参数和一个callback回调函数作为参数。当greet函数被调用时,它会先输出一条问候语,然后调用callback回调函数。在这个例子中,sayGoodbye函数被作为回调函数传递给greet函数,并在greet函数内部被调用。

    3)什么是回调地狱?

        回调地狱(Callback Hell)是指在编写异步JavaScript代码时,回调函数嵌套的现象越来越深,导致代码的可读性变差、维护性变差、复杂度增加、错误率增加等问题。回调地狱通常表现为深度嵌套并且难以阅读的代码,例如:

    1. //跟以前的if条件地狱很像
    2. // if(){
    3. // if(){
    4. // if(){
    5. // }
    6. // }
    7. // }
    8. $.get("/getUser",function(res){
    9. $.get("/getUserDetail",function(){
    10. $.get("/getCart",function(){
    11. $.get("/getBooks",function(){
    12. //...
    13. })
    14. })
    15. })
    16. })
    17. //node开发:读取文件;开个服务器、接收一个请求、请求路径、访问数据库

    2 Promise函数基本用法

         例1:下面代码是一个使用 Promise 来封装异步操作(在这个例子中是使用 jQuery 的 $.get 方法来发送一个 GET 请求到 "/getUser")的例子:执行顺序:abcd

    1. var promise=new Promise((resolve,reject)=>{
    2. //b 把需要执行的异步操作放在这里
    3. $.get("/getUser",res=>{
    4. //获取数据的异步操作已经执行完毕了,等待下一步的执行,通过执行resolve函数,告诉外界你可以执行下一步操作了
    5. //c、
    6. resolve(res)
    7. //而执行的下一步操作,其实就是写在then的回调函数中的
    8. })
    9. })
    10. //a、
    11. promise.then(res=>{
    12. //d、执行后续的操作
    13. console.log(res);
    14. })

    1)创建 Promise

    1. var promise = new Promise((resolve, reject) => {
    2. // ...
    3. });

          这里,创建了一个Promise 实例。Promise 是一个对象,它代表一个最终可能完成(也可能被拒绝)的异步操作及其结果值。Promise 构造函数接受一个执行器函数,这个函数有两个参数:resolve 和 reject。这两个函数都是用于改变 Promise 状态的。

    2)执行异步操作

    1. $.get("/getUser", res => {
    2. // ...
    3. resolve(res);
    4. });

          在 Promise 的执行器函数内部,使用 jQuery 的 $.get 方法发送了一个 GET 请求到 "/getUser"。当请求成功时,jQuery 会调用提供的回调函数,并传入响应数据 res。在这个回调函数中,调用了 resolve 函数,并将响应数据 res 作为参数传递给它。这表示异步操作已经成功完成,并且这里有一个结果值要返回给 Promise 的调用者。

    3)处理 Promise 的结果

    1. promise.then(res => {
    2. // ...
    3. console.log(res);
    4. });

      使用 promise.then() 方法,你指定了一个回调函数来处理 Promise 的结果。当 Promise 的状态变为 "fulfilled"(即 resolve 函数被调用)时,这个回调函数会被执行,并且 resolve 函数的参数(在这个例子中是 res)会被作为回调函数的参数。在这个例子中,回调函数只是简单地打印了响应数据 res 到控制台。

         例2:读代码,感受promise的基本用法

    1. <script>
    2. //把异步操作封装在一个promise对象中
    3. function fn(){
    4. return new Promise((resolve,reject)=>{
    5. setTimeout(()=>{
    6. console.log('你好');
    7. //其实异步逻辑到这里其实已经执行完毕了,
    8. //就可以告诉外界,可以执行其他操作了
    9. //如何告诉外界,让外界得知?
    10. resolve();
    11. },1000);
    12. })
    13. }
    14. //调用了这个函数,执行了异步操作
    15. //fn()
    16. //存在问题,并不知道这个异步操作什么时候结束
    17. fn().then(res=>{
    18. //执行到下一步
    19. console.log("下一步");
    20. fn().then(res=>{
    21. console.log("执行第二步");
    22. })
    23. })
    24. //输出顺序:
    25. //你好
    26. //下一步
    27. //你好
    28. //执行第二步
    29. </script>

    3 Promise函数实现多层回调

    -解决回调地狱

        例1:-> 获取用户 -> 获取用户基本信息 -> 查看用户详情 -> 查看购物车信息

    1. new Promise((resolve,reject)=>{
    2. $.get("/getUser",res=>{
    3. resolve(res)
    4. })
    5. }).then(res=>{
    6. //用户基本信息
    7. return new Promise(resolve=>{
    8. $.get("/getUserDetail",res=>{
    9. resolve(res)
    10. })
    11. })
    12. }).then(res=>{
    13. //用户详情
    14. return new Promise(resolve=>{
    15. $.get("/getCart",res=>{
    16. resolve(res)
    17. })
    18. })
    19. }).then(res=>{
    20. //购物车信息
    21. })

      例2:第一步 -> 第二步 -> 第一步 -> 第二步 -> 完成

    1. <script>
    2. function f1(){
    3. return new Promise(resolve=>{
    4. setTimeout(()=>{
    5. console.log('第一步');
    6. //异步逻辑已经执行完,必须要告诉外界我执行完了
    7. resolve();
    8. },1000)
    9. })
    10. }
    11. function f2(){
    12. return new Promise(resolve=>{
    13. setTimeout(()=>{
    14. console.log('第二步');
    15. //告诉外界我执行完了
    16. resolve();
    17. },1000)
    18. })
    19. }
    20. f1().then(res=>{
    21. //返回一个promise对象
    22. return f2();
    23. }).then(res=>{
    24. return f1();
    25. }).then(res=>{
    26. return f2();
    27. }).then(res=>{
    28. setTimeout(()=>{
    29. console.log('完成');
    30. },1000)
    31. })
    32. </script>

     4 Promise传参

    1. function getUser(){
    2. return new Promise(resolve=>{
    3. $.get("/getUser",res=>{
    4. //res是从服务器中接收到的数据
    5. //把数据传到下一步操作中
    6. //告诉外界本次的异步操作已经执行完毕了
    7. resolve(res)
    8. })
    9. })
    10. }
    11. getUser().then(res=>{
    12. //res就表示上一个异步操作返回的参数值:从服务器中获取的数据
    13. })

    Promise 错误处理

    5.1 两种错误处理方式

     第一种方式,then里包含成功、失败两个返回值

    1. new Promise((resolve,reject)=>{
    2. $.ajax({
    3. url:"/getUser",
    4. type:"GET",
    5. success:res=>{
    6. resolve(res);
    7. },
    8. error:res=>{
    9. reject(res)
    10. }
    11. })
    12. }).then(resSuccess=>{
    13. //成功的返回值
    14. },resError=>{
    15. //失败的返回值
    16. })

    第二种方式:catch(推荐)

    1. new Promise((resolve,reject)=>{
    2. $.ajax({
    3. url:"/getUser",
    4. type:"GET",
    5. success:res=>{
    6. resolve(res);
    7. },
    8. error:res=>{
    9. reject(res)
    10. }
    11. })
    12. }).then(resSuccess=>{
    13. //成功的返回值
    14. }).catch(resError=>{
    15. //失败的返回值
    16. })

    小结:上面2种错误处理的方式,第二种更加推荐。第二种方式更强大的地方在于:

        a、不仅仅可以捕获到reject传递的参数

        b、还可以捕获到:成功的回调中发生的错误

    样例:

    1. <script>
    2. function getBooks(){
    3. //执行了resolve()表示异步操作是成功的
    4. //执行了reject()表示异步操作是失败的
    5. return new Promise((resolve,reject)=>{
    6. $.ajax({
    7. url:"/getBooks",
    8. success(res){
    9. //成功获取数据
    10. resolve(res);
    11. },
    12. error(resError){ //res表示错误信息
    13. //如果失败,执行error方法
    14. //通过执行reject函数,把错误信息传递给外界
    15. reject(resError)
    16. }
    17. })
    18. })
    19. }
    20. //第一种处理错误的方式:
    21. // getBooks().then(res=>{
    22. // //res表示请求成功时候获取到的数据
    23. // },resError=>{
    24. // console.log(resError);
    25. // })
    26. //第二种错误处理的方式:
    27. // getBooks().then(res=>{
    28. // //成功了
    29. // }).catch(resError=>{
    30. // //这里也可以获取到错误信息
    31. // })
    32. </script>

    5.2 catch捕获错误

          catch不仅能捕获错误信息,还能捕获到成功后的代码错误信息

    setTimeout 来模拟异步操作。这个异步操作将在 1 秒(1000 毫秒)后完成

    1. function f1(name){
    2. return new Promise((resolve,reject)=>{
    3. setTimeout(()=>{
    4. if(name=="a"){
    5. resolve("成功");
    6. }else{
    7. reject("失败")
    8. }
    9. },1000)
    10. })
    11. }

    then里处理

    1. f1("b").then(res=>{
    2. console.log('成功了');
    3. },resError=>{
    4. console.log('失败了');
    5. })

    catch处理

    1. f1("b").then(res=>{
    2. console.log('成功了');
    3. }).catch(res=>{
    4. console.log('失败了');
    5. })

    catch处理成功信息里出现代码错误

    1. f1("a").then(res => {
    2. var a = 5;
    3. a(); //这里代码发生了错误
    4. }).catch(res => {
    5. //成功的捕捉到了成功回调中的代码错误
    6. console.log(res);
    7. })

    效果(打印错误,控制台没出现红色报错信息)

    5.3 多层异步种使用catch

        例1:首先执行第一步-> 成功-> 第二步-> 失败-> 

    1. new Promise((resolve,reject)=>{
    2. setTimeout(()=>{
    3. console.log('第一步');
    4. resolve("第一步完成")
    5. },100)
    6. }).then(res=>{
    7. console.log(res); //res:第一步完成
    8. return new Promise((resolve,reject)=>{
    9. setTimeout(()=>{
    10. console.log('第二步');
    11. reject('第二步失败');
    12. },100)
    13. })
    14. }).then(res=>{
    15. //并不会执行到这里
    16. console.log('第二步成功');
    17. }).catch(res=>{
    18. console.log(res);
    19. })

    效果:

          拓展: axios就是一个基于Promise封装出来的进行ajax请求的库

    1. axios.get("/getUser").then(res=>{
    2. return axios.get("/getUserDetail")
    3. }).get("/getLoginInfo").then(res=>{
    4. console.log('');
    5. })

    6 使用 Promise 的优势

    1. 代码结构更清晰:Promise 允许我们将异步操作的组织方式从传统的嵌套回调(callback hell)转变为链式调用,这使得代码结构更加清晰,易于理解和维护。

    2. 错误处理更简洁:传统的嵌套回调中,错误处理通常需要在每个回调函数中显式地添加错误处理逻辑。而 Promise 提供了 .catch() 方法,可以一次性捕获多个异步操作中的错误,使错误处理更加简洁和统一。

    3. 支持链式调用:Promise 支持链式调用,可以通过 .then() 方法将多个异步操作串联起来,形成一个执行流程。这使得异步代码更加易于组织和管理,提高了代码的可读性和可维护性。

    4. 更好的可读性和可维护性:Promise 的语法更接近于同步代码,使得异步代码的阅读和编写更加直观。此外,Promise 还支持 ES6 的 async/await 语法,可以将异步代码转换为看起来更像同步代码的形式,进一步提高了代码的可读性和可维护性。

    5. 更好的返回值处理:Promise 的 resolve 方法可以传递任何类型的值(包括其他 Promise),这使得我们可以更加灵活地处理异步操作的返回值。在多层回调中,通常需要手动处理每个回调函数的返回值,而在 Promise 中,我们可以使用 .then() 方法来统一处理返回值。

    6. 可取消的异步操作(虽然 Promise 本身不直接支持取消,但可以通过扩展 Promise 或者使用其他库来实现):在某些情况下,我们可能需要取消正在进行的异步操作。虽然 Promise 本身并不直接支持取消操作,但我们可以通过扩展 Promise 或者使用其他库(如 Bluebird)来实现取消功能。

    7. 更好的组合和复用:Promise 提供了 Promise.all()Promise.race() 等静态方法,允许我们更方便地对多个 Promise 进行组合和复用。这些功能在多层回调中很难实现。

  • 相关阅读:
    一文带你走进 Linux 小工具 - tmux
    Oracle 进阶详细案例教程笔记
    Amazon EC2 部署Ollama + webUI
    Maven多模块版本统一管理
    思考型人格分析,思考型人格的职业发展方向
    Linux云服务器:MySQL安装失败、多种错误总结 | 个人解决参考
    【电脑讲解】电脑如何实现双系统
    2023年软件测试之功能测试(完整版)
    MFC Windows 程序设计[244]之简单的偏好(附源码)
    MySQL 的 ORDER BY 排序内部原理
  • 原文地址:https://blog.csdn.net/m0_68467925/article/details/139389797