本课聚焦JavaScript异步编程进阶核心Promise,针对回调地狱的痛点,讲解Promise的状态机制、基础语法与链式调用。Promise通过pending、fulfilled、rejected三种状态管理异步流程,用then/catch替代嵌套回调,让代码结构更清晰、更易维护。课程结合单词查询场景,拆解基础封装、串行链式、并行执行三类案例,帮助掌握Promise的实战用法。Promise是前端异步处理的标准方案,也是面试高频考点,更是后续学习async/await的必备基础。掌握本课内容,既能解决项目中的异步嵌套问题,又能建立规范的异步编程思维,为前端工程化开发打下关键基础。

一、课程学习目的

  1. 回顾回调函数的弊端,深刻理解回调地狱对代码维护的影响。

  2. 掌握Promise的核心概念、三种状态流转机制,吃透异步处理的底层逻辑。

  3. 熟练使用Promise基础语法、then/catch/finally链式调用,规范处理异步结果。

  4. 学会Promise.all、Promise.race等常用API,实现异步任务串行与并行执行。

  5. 能够封装Promise异步函数,替代传统回调写法,为后续async/await学习筑牢基础。

二、核心知识点讲解

1. 回调地狱与Promise诞生

上一课学习的回调函数,在处理多层异步任务时会形成横向嵌套的回调地狱,导致代码可读性差、难以调试、维护成本极高。

Promise是ES6推出的异步处理对象,通过状态管理和链式调用,将嵌套回调改写为线性结构,彻底解决回调地狱问题,让异步代码更接近同步写法。

2. Promise的三种状态(不可逆)

  • pending(等待态):初始状态,异步任务执行中,未得到结果

  • fulfilled(成功态):异步任务完成,调用resolve方法,触发then处理结果

  • rejected(失败态):异步任务失败,调用reject方法,触发catch捕获错误

状态一旦从pending变为fulfilled/rejected,就会固定不变,无法再次修改。

3. Promise基础语法与执行流程

创建Promise实例时,需要传入一个执行器函数,内部包含resolve和reject两个参数,分别用于标记成功和失败。

调用Promise实例后,通过then接收成功结果,catch捕获异常错误,finally无论成功失败都会执行。

4. Promise核心API与用法

  • .then():处理成功态结果,支持返回新Promise,实现链式调用

  • .catch():捕获失败态错误,全局捕获整条链的异常

  • .finally():收尾执行,常用于关闭加载、清理状态

  • Promise.all():并行执行多个Promise,全部成功才返回结果

  • Promise.race():并行执行多个Promise,以最快完成的结果为准

三、示例程序

示例1:Promise基础封装(异步查询单词)

// 封装异步获取单词的Promise函数
function getWordInfo(word) {
  // 返回Promise实例
  return new Promise((resolve, reject) => {
    // 模拟网络请求延迟
    setTimeout(() => {
      // 判断异步任务是否成功
      if (word && typeof word === 'string') {
        // 成功:返回单词数据
        resolve({ en: word, cn: '中文释义', status: 'success' });
      } else {
        // 失败:返回错误信息
        reject(new Error('单词参数无效,获取失败'));
      }
    }, 1000);
  });
}

// 调用Promise并处理结果
getWordInfo('apple')
  .then(res => {
    console.log('获取成功:', res);
  })
  .catch(err => {
    console.error('获取失败:', err.message);
  })
  .finally(() => {
    console.log('异步任务执行完毕');
  });

示例2:Promise链式调用(串行获取单词)

// 链式调用,按顺序执行异步任务
getWordInfo('apple')
  .then(res => {
    console.log('第一个单词:', res.en);
    // 返回新Promise,继续下一个任务
    return getWordInfo('banana');
  })
  .then(res => {
    console.log('第二个单词:', res.en);
    return getWordInfo('orange');
  })
  .then(res => {
    console.log('第三个单词:', res.en);
  })
  // 全局捕获整条链的错误
  .catch(err => {
    console.error('任务中断:', err.message);
  });

示例3:Promise.all并行获取单词

// 创建多个Promise任务
const task1 = getWordInfo('apple');
const task2 = getWordInfo('banana');
const task3 = getWordInfo('grape');

// 并行执行,全部完成后统一处理
Promise.all([task1, task2, task3])
  .then(results => {
    console.log('全部单词获取成功:', results);
  })
  .catch(err => {
    console.error('有任务失败:', err.message);
  });

四、掌握技巧与方法

  1. 异步耗时任务(定时器、接口请求、文件加载)优先用Promise封装,替代回调函数。

  2. 牢记Promise状态不可逆,resolve和reject仅能调用一次,避免重复触发。

  3. 链式调用时,then内部需返回新Promise,否则无法实现异步串行。

  4. 必须添加catch捕获错误,防止未处理的Promise异常导致代码崩溃。

  5. 多个无依赖异步任务用Promise.all并行执行,提升效率;有依赖任务用链式串行。

  6. 调试时重点观察状态流转,区分pending、fulfilled、rejected的执行时机。

五、课后作业

基础作业

  1. 用Promise封装定时器异步任务,1.5秒后返回指定数据。

  2. 调用Promise,分别测试成功、失败两种场景,验证then和catch的执行逻辑。

  3. 使用finally方法,测试异步任务完成后的收尾逻辑。

进阶作业

  1. 实现Promise链式调用,按顺序获取3组单词数据。

  2. 用Promise.all并行加载多个单词,处理全部成功的场景。

  3. 模拟异步失败场景,验证catch的全局捕获能力。

实战作业

  1. 搭建可视化异步单词加载页面,用Promise封装异步逻辑,实现单个加载、串行加载、并行加载功能,搭配加载状态和错误提示,完成完整实战。

上一课:异步编程基础(回调函数)实战作业

代码功能说明

本实战代码围绕回调函数核心知识点,贴合英语单词场景设计,可直接在浏览器运行。代码封装了同步回调、异步定时器回调、事件回调三类函数,模拟单词同步处理、延迟加载、点击触发加载的逻辑,直观展示同步与异步代码的执行顺序差异,演示回调函数处理异步结果的流程,同时通过多层嵌套回调展现回调地狱的结构,帮助理解回调函数的用法与弊端。页面配备功能按钮,点击可分步演示不同回调场景,结果实时渲染,全程衔接第14课知识点,为后续学习Promise做好铺垫。

注意事项

  • 同步代码优先级高于异步代码,异步回调会在主线程空闲后执行,需牢记执行顺序。

  • 回调函数需在异步任务完成后调用,确保结果获取准确,避免时序错误。

  • 多层嵌套回调会形成回调地狱,导致代码可读性差,仅用于理解痛点,项目不推荐使用。

  • 异步任务的错误需通过回调参数传递,无法直接用try/catch捕获,需做好异常判断。

  • 回调函数内部this易指向全局,可通过箭头函数或缓存this变量修正指向。

  • 运行代码时打开浏览器控制台,可更清晰观察异步执行流程与回调触发时机。

  • 本案例为基础入门,复杂异步场景建议使用后续课程的Promise方案优化。

完整实战代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>第14课 回调函数实战 - 单词加载器</title>
    <style>
        .box {
            width: 700px;
            margin: 50px auto;
            padding: 25px;
            border: 1px solid #eee;
            border-radius: 10px;
            font-family: "Microsoft YaHei";
            box-shadow: 0 0 10px rgba(0,0,0,0.05);
        }
        .btn {
            padding: 10px 18px;
            margin: 10px 8px;
            background: #42b983;
            color: #fff;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            transition: 0.3s;
        }
        .btn:hover {
            background: #359469;
        }
        .result {
            margin-top: 25px;
            padding: 15px;
            line-height: 2;
            border-top: 1px dashed #eee;
            min-height: 150px;
        }
        .item {
            margin: 8px 0;
            padding: 10px;
            background: #f9f9f9;
            border-radius: 5px;
        }
    </style>
</head>
<body>
    <div class="box">
        <h2>单词加载器(回调函数版)</h2>
        <button class="btn" onclick="testSyncCallback()">同步回调</button>
        <button class="btn" onclick="testAsyncCallback()">异步回调</button>
        <button class="btn" onclick="testCallbackHell()">回调地狱演示</button>
        <button class="btn" onclick="clearResult()">清空结果</button>
        <div class="result" id="result"></div>
    </div>

    <script>
        const resultDom = document.getElementById("result");
        // 渲染结果到页面
        function render(html) {
            resultDom.innerHTML += `<div class="item">${html}</div>`;
        }

        // 1. 同步回调函数
        function getWord(word, callback) {
            callback(word);
        }
        function testSyncCallback() {
            getWord("apple", function(res) {
                render(`同步回调结果:获取单词 - ${res}`);
            });
            render("同步代码执行完毕");
        }

        // 2. 异步回调函数(定时器模拟)
        function getWordAsync(word, delay, callback) {
            render(`正在异步加载单词:${word},延迟${delay}ms`);
            setTimeout(() => {
                callback(res);
            }, delay);
        }
        function testAsyncCallback() {
            getWordAsync("banana", 1500, function(res) {
                render(`异步回调结果:获取单词 - ${res}`);
            });
            render("异步任务已发起,继续执行同步代码");
        }

        // 3. 回调地狱演示(多层嵌套)
        function testCallbackHell() {
            getWordAsync("apple", 1000, function(res1) {
                render(res1);
                getWordAsync("banana", 1000, function(res2) {
                    render(res2);
                    getWordAsync("orange", 1000, function(res3) {
                        render(res3);
                    });
                });
            });
        }

        // 清空结果
        function clearResult() {
            resultDom.innerHTML = "";
        }
    </script>
</body>
</html>

作业验收标准

  1. 所有按钮点击正常执行,浏览器控制台无报错。

  2. 同步回调、异步回调结果展示准确,执行顺序符合异步编程规则。

  3. 回调地狱演示清晰展现多层嵌套结构,直观体现代码可读性问题。

  4. 代码规范,注释完整,贴合第14课回调函数核心知识点。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐