• 谷粒商城实战笔记-34-前端基础-ES6-promise异步编排



    在ES6中,Promise是一个用于异步编程的重要构造,它代表了一个最终可能完成或失败的异步操作,并且具有一个最终的值。

    简单的说,Promise提供了一种新的异步调用的语法,让异步调用的语法更加简洁和容易理解。

    接下里,我们将以一个例子深入浅出的说清楚Promise的来龙去脉。

    一,回调地狱(Callback Hell)

    回调地狱也被称为金字塔之痛(Pyramid of Doom),是在使用回调函数进行异步编程时遇到的一个常见问题。

    在JavaScript中,回调函数经常被用来处理异步操作的结果,如网络请求、定时器、文件I/O等。

    当多个异步操作需要按顺序执行,并且每个操作依赖于前一个操作的结果时,代码中可能会出现多层嵌套的回调函数,这会导致代码结构变得非常复杂和难以维护。

    例如,考虑以下伪代码:

    someAsyncOperation(function(result1) {
      anotherAsyncOperation(result1, function(result2) {
        yetAnotherAsyncOperation(result2, function(result3) {
          // ...更多的嵌套...
        });
      });
    });
    

    在这个例子中,每个异步操作都必须在其完成后调用一个回调函数,而这个回调函数可能又会触发另一个异步操作。这种深度嵌套的结构会导致代码变得难以阅读和调试,尤其是当异步操作的数量增加时。

    回调地狱的几个主要问题包括:

    • 可读性差:代码的逻辑流程不易追踪,因为控制流被分割成许多嵌套的块。
    • 难以维护:修改代码或添加新的异步操作可能需要深入到多层嵌套中,这增加了引入错误的风险。
    • 错误处理复杂:在多层嵌套中处理错误通常需要在每个回调中重复错误处理代码,这可能导致代码冗余和潜在的遗漏。

    为了解决回调地狱问题,现代JavaScript引入了更好的异步编程模型,如Promises和async/await语法。这些新特性提供了一种更简洁、更线性的方式来处理异步操作,减少了代码的复杂度,同时提高了可读性和可维护性。例如,使用Promises,上面的例子可以重写为:

    someAsyncOperation()
      .then(result1 => anotherAsyncOperation(result1))
      .then(result2 => yetAnotherAsyncOperation(result2))
      .then(result3 => {
        // ...处理result3...
      })
      .catch(error => {
        // ...统一处理错误...
      });
    

    或者使用async/await:

    async function doOperations() {
      try {
        const result1 = await someAsyncOperation();
        const result2 = await anotherAsyncOperation(result1);
        const result3 = await yetAnotherAsyncOperation(result2);
        // ...处理result3...
      } catch (error) {
        // ...统一处理错误...
      }
    }
    

    这些替代方案极大地改善了代码的结构和可读性,使得异步编程变得更加优雅和直观。

    二,实战Promise

    1,场景说明

    假设有这样一个需求,学生登录学校的考试系统,查询某一个的成绩。

    实现这个简单的需求,要发出三次请求。

    • 第一次请求,根据用户名查询用户ID,查询成功说明可以登录
    • 第一次请求成功后,发出第二次请求,查询该用户有成绩的科目ID
    • 第二次请求成功后,发出第三次请求,根据科目ID查询成绩

    假设后台的数据存储在json文件中,整个请求过程如下。

    第一次请求从后台的user.json文件中查询到用户的ID为1。

    // user.json:
    {
    	"id": 1,
    	"name": "zhangsan",
    	"password": "123456"
    }
    

    第二次请求从后台的user_corse_1.json中查询到用户有成绩的课程ID为10。

    // user_corse_1.json:
    {
    	"id": 10,
    	"name": "chinese"
    }
    

    第三次请求从后台的corse_score_10.json中查询到用户课程ID成绩为90。

    corse_score_10.json:
    {
    	"id": 100,
    	"score": 90
    }
    

    在这里插入图片描述

    2,回调地狱-传统实现

    假设我们用JQuery的ajax实现异步请求,代码如下。

    html代码完整代码如下,后续的JS演示代码都放在