Promise().then().catch().finally() 笔记250804

118 阅读15分钟

Promise().then().catch().finally() 笔记250804

Promise.then().catch().finally() 方法详解

Promise 是 JavaScript 异步编程的核心,其链式调用方法 .then().catch().finally() 提供了强大的异步控制能力。我将全面解析这些方法的工作原理、使用场景和最佳实践。

核心方法概述

方法作用参数返回值
.then()处理成功状态onFulfilled, onRejected新 Promise
.catch()处理失败状态onRejected新 Promise
.finally()最终清理操作onFinally新 Promise

完整语法结构

promise
  .then(
    onFulfilled?: (value) => any,
    onRejected?: (reason) => any
  )
  .catch(
    onRejected?: (reason) => any
  )
  .finally(
    onFinally?: () => any
  );

方法详解

     1. .then() - 处理异步结果

const promise = new Promise((resolve, reject) => {
  setTimeout(() => resolve("成功数据"), 1000);
});

promise.then(
  result => {
    console.log("成功:", result); // "成功: 成功数据"
    return result.toUpperCase();
  },
  error => {
    console.error("失败:", error);
    return "默认值";
  }
).then(newResult => {
  console.log("第二次处理:", newResult); // "第二次处理: 成功数据"
});

特点

  • 接收两个可选参数:成功回调和失败回调
  • 返回新 Promise,支持链式调用
  • 回调函数返回值决定新 Promise 状态:
    • 返回普通值 → 新 Promise 成功状态
    • 抛出错误 → 新 Promise 失败状态
    • 返回 Promise → 继承该 Promise 状态

     2. .catch() - 错误处理

const failingPromise = new Promise((resolve, reject) => {
  setTimeout(() => reject(new Error("请求超时")), 1000);
});

failingPromise
  .then(result => {
    console.log("成功结果:", result);
  })
  .catch(error => {
    console.error("捕获错误:", error.message); // "捕获错误: 请求超时"
    return "错误恢复值";
  })
  .then(result => {
    console.log("恢复后结果:", result); // "恢复后结果: 错误恢复值"
  });

特点

  • 专门处理 Promise 链中的错误
  • 相当于 .then(null, onRejected)
  • 捕获链中所有前面的错误
  • 返回新 Promise,可恢复执行链

     3. .finally() - 最终清理

let isLoading = true;

fetchData()
  .then(data => {
    console.log("数据获取成功:", data);
  })
  .catch(error => {
    console.error("数据获取失败:", error);
  })
  .finally(() => {
    isLoading = false;
    console.log("清理完成,无论成功或失败");
  });

特点

  • 无论成功/失败都会执行
  • 不接收任何参数(不知道最终状态)
  • 不影响 Promise 链的值传递
  • 通常用于清理操作(关闭加载、清理资源)

完整工作流程

graph TD
    A[Promise 创建] --> B{状态}
    B -->|fulfilled| C[执行 .then 第一个回调]
    B -->|rejected| D[执行 .then 第二个回调或 .catch]
    C --> E[返回新值?]
    D --> E
    E --> F[创建新 Promise]
    F --> G[执行 .finally]
    G --> H[传递原始值]

使用场景与最佳实践

     1. 顺序异步操作

function getUserData(userId) {
  return fetchUser(userId)
    .then(user => fetchProfile(user.id))
    .then(profile => fetchPosts(profile.id))
    .then(posts => {
      console.log("用户帖子:", posts);
      return posts;
    });
}

// async/await 等效写法
async function getUserDataAsync(userId) {
  try {
    const user = await fetchUser(userId);
    const profile = await fetchProfile(user.id);
    return await fetchPosts(profile.id);
  } catch (error) {
    handleError(error);
  }
}

     2. 错误恢复策略

fetchPrimaryData()
  .catch(() => {
    console.warn("主数据源失败,尝试备用源");
    return fetchFallbackData();
  })
  .then(data => processData(data))
  .catch(error => {
    console.error("所有数据源失败");
    throw error;
  });

     3. 资源管理与清理

let dbConnection;

openDatabase()
  .then(connection => {
    dbConnection = connection;
    return connection.query("SELECT * FROM users");
  })
  .then(users => {
    console.log("用户数据:", users);
  })
  .catch(error => {
    console.error("数据库错误:", error);
  })
  .finally(() => {
    if (dbConnection) {
      dbConnection.close();
      console.log("数据库连接已关闭");
    }
  });

     4. 组合使用示例

function processPayment(order) {
  let paymentProcessed = false;
  
  return validateOrder(order)
    .then(validatedOrder => {
      return chargeCreditCard(validatedOrder);
    })
    .then(paymentResult => {
      paymentProcessed = true;
      return updateOrderStatus(order.id, "paid");
    })
    .then(() => {
      return sendConfirmationEmail(order.customerEmail);
    })
    .catch(error => {
      if (paymentProcessed) {
        console.error("支付后出错,发起退款");
        return initiateRefund(order.id);
      }
      throw error;
    })
    .finally(() => {
      cleanPaymentSession(order.id);
    });
}

常见陷阱与解决方案

     1. 错误处理不完整

问题

// 无法捕获 JSON 解析错误
fetch('/data')
  .then(response => response.json())
  .then(data => console.log(data));

解决方案

fetch('/data')
  .then(response => {
    if (!response.ok) throw new Error('网络响应错误');
    return response.json();
  })
  .then(data => console.log(data))
  .catch(error => console.error('处理失败:', error));

     2. Promise 链中断

问题

// 错误被捕获但未传递
fetchData()
  .catch(error => console.error(error))
  .then(data => {
    // 即使前面出错这里仍会执行
  });

解决方案

fetchData()
  .catch(error => {
    console.error(error);
    // 重新抛出以中断链条
    throw error; 
    // 或返回拒绝的 Promise
    // return Promise.reject(error);
  })
  .then(data => {
    // 仅在前一步成功时执行
  });

     3. finally 中的返回值

问题

Promise.resolve('原始值')
  .finally(() => {
    return '新值'; // 被忽略
  })
  .then(value => console.log(value)); // "原始值"

Promise.resolve('原始值')
  .finally(() => {
    throw new Error('finally错误'); // 会覆盖
  })
  .catch(e => console.log(e.message)); // "finally错误"

解决方案

// 正确使用 finally - 仅用于清理
let resource;

allocateResource()
  .then(res => {
    resource = res;
    return useResource(res);
  })
  .finally(() => {
    if (resource) releaseResource(resource);
  });

高级应用模式

     1. 超时控制

function withTimeout(promise, timeout) {
  return Promise.race([
    promise,
    new Promise((_, reject) => 
      setTimeout(() => reject(new Error('操作超时')), timeout)
    )
  ]);
}

withTimeout(fetchData(), 3000)
  .then(data => console.log('数据:', data))
  .catch(error => console.error('错误:', error.message));

     2. 批处理与并发控制

function processInBatches(items, batchSize, processItem) {
  const batches = [];
  for (let i = 0; i < items.length; i += batchSize) {
    batches.push(items.slice(i, i + batchSize));
  }
  
  return batches.reduce((promiseChain, batch) => {
    return promiseChain.then(() => {
      return Promise.all(batch.map(processItem));
    });
  }, Promise.resolve());
}

     3. 重试机制

function retry(fn, retries = 3, delay = 1000) {
  return new Promise((resolve, reject) => {
    fn()
      .then(resolve)
      .catch(error => {
        if (retries <= 0) return reject(error);
        
        setTimeout(() => {
          retry(fn, retries - 1, delay * 1.5)
            .then(resolve)
            .catch(reject);
        }, delay);
      });
  });
}

与 async/await 的关系

// Promise 链
function fetchData() {
  return fetch('/data')
    .then(response => response.json())
    .then(data => process(data))
    .catch(error => handleError(error));
}

// async/await 等价写法
async function fetchDataAsync() {
  try {
    const response = await fetch('/data');
    const data = await response.json();
    return process(data);
  } catch (error) {
    handleError(error);
  }
}

关键区别

  • async/await 是语法糖,底层仍使用 Promise
  • Promise 链更灵活处理并行操作
  • async/await 更直观处理顺序操作

浏览器兼容性

方法ChromeFirefoxSafariEdge
.then()3229812
.catch()3229812
.finally()635811.118

对于旧浏览器,可使用 Polyfill:

// 简单的 finally polyfill
if (!Promise.prototype.finally) {
  Promise.prototype.finally = function(callback) {
    return this.then(
      value => Promise.resolve(callback()).then(() => value),
      reason => Promise.resolve(callback()).then(() => { throw reason; })
    );
  };
}

最佳实践总结

  1. 链式顺序

    // 推荐顺序
    promise
      .then(handleSuccess)
      .catch(handleError)
      .finally(cleanup);
    
  2. 错误处理

    • 每个 Promise 链至少有一个 .catch()
    • 在适当层级处理特定错误
  3. 资源清理

    • 使用 .finally() 确保清理逻辑执行
    • 避免在 .finally() 中返回数据
  4. 链式优化

    // 避免不必要的嵌套
    // 不推荐
    promise.then(result1 => {
      return process1(result1).then(result2 => {
        // 深层嵌套
      });
    });
    
    // 推荐
    promise
      .then(process1)
      .then(result2 => {
        // 扁平结构
      });
    
  5. 混合使用

    // 合理结合 async/await
    async function combinedExample() {
      try {
        const data = await fetchData();
        return processData(data)
          .then(result => sendResult(result))
          .catch(sendError);
      } catch (error) {
        handleInitialError(error);
      }
    }
    

Promise 的 .then().catch().finally() 方法提供了强大的异步控制能力。掌握它们的使用模式和最佳实践,可以编写出更健壮、更易维护的异步 JavaScript 代码。







实例讲解

例一: 例一代码:

new Promise( (resolve, reject)=>{
	resolve("resolve","的","参数");
	reject("reject","的","参","数");
}).then(
	(v0,v1,v2) => console.log(v0,v1,v2,"从then的第一个函数参数执行的输出")
	,
	(v0,v1,v2,v3) => console.log(v0,v1,v2,v3,"从then的第二个函数参数执行的输出")
).catch(
	(v0,v1,v2,v3) => console.log(v0,v1,v2,v3, "从catch的第一个函数参数执行的输出")
)

例一结果输出:

resolve undefined undefined 从then的第一个函数参数执行的输出

例一讲解

new Promise( (resolve, reject)=>{
	resolve("resolve","的","参数");        //////// 结果 "resolve undefined undefined" 反映resolve只能传递一个参数
	reject("reject","的","参","数");        //////// 没有执行, 执行了 resolve 就不会再执行 reject
}).then(
	(v0,v1,v2) => console.log(v0,v1,v2,"从then的第一个函数参数执行的输出")        //////// 输出了这条结果
	,
	(v0,v1,v2,v3) => console.log(v0,v1,v2,v3,"从then的第二个函数参数执行的输出")
).catch(
	(v0,v1,v2,v3) => console.log(v0,v1,v2,v3, "从catch的第一个函数参数执行的输出")
)

从例一看出:

  • resolve只能放入一个参数, 多余的参数不会传递下去
  • 执行resolve后, reject不会执行




例二: 例二代码: 与 例一 的唯一区别是调换了 resolvereject 的执行顺序

new Promise( (resolve, reject)=>{
	resolve("resolve","的","参数");
	reject("reject","的","参","数");
}).then(
	(v0,v1,v2) => console.log(v0,v1,v2,"从then的第一个函数参数执行的输出")
	,
	(v0,v1,v2,v3) => console.log(v0,v1,v2,v3,"从then的第二个函数参数执行的输出")
).catch(
	(v0,v1,v2,v3) => console.log(v0,v1,v2,v3, "从catch的第一个函数参数执行的输出")
)

例二结果输出:

reject undefined undefined undefined 从then的第二个函数参数执行的输出

例二讲解

new Promise( (resolve, reject)=>{
	reject("reject","的","参","数");        ////////  结果 "reject undefined undefined undefined" 反映reject只能传递一个参数
	resolve("resolve","的","参数");        //////// 没有执行, 执行了 reject 就不会再执行 resove
}).then(
	(v0,v1,v2) => console.log(v0,v1,v2,"从then的第一个函数参数执行的输出")
	,
	(v0,v1,v2,v3) => console.log(v0,v1,v2,v3,"从then的第二个函数参数执行的输出")        //////// 输出了这条结果
).catch(
	(v0,v1,v2,v3) => console.log(v0,v1,v2,v3, "从catch的第一个函数参数执行的输出")        //////// 没有执行, 因为在then的第二个参数执行过了
)

从例二看出:

  • rejectresolve一样只能放入一个参数, 多余的参数不会传递下去
  • 执行reject后, resolve不会执行
  • 如果then使用了两个参数, then的第二个函数参数执行过了,就不会再执行catch的函数参数




例三: 例三代码: 与 例二 的唯一区别是注释了then的第二个函数参数(只用一个参数),留给catch

new Promise( (resolve, reject)=>{
	resolve("resolve","的","参数");
	reject("reject","的","参","数");
}).then(
	(v0,v1,v2) => console.log(v0,v1,v2,"从then的第一个函数参数执行的输出")
	//,
	//(v0,v1,v2,v3) => console.log(v0,v1,v2,v3,"从then的第二个函数参数执行的输出")
).catch(
	(v0,v1,v2,v3) => console.log(v0,v1,v2,v3, "从catch的第一个函数参数执行的输出")
)

例三结果输出:

reject undefined undefined undefined 从catch的第一个函数参数执行的输出

例三讲解

new Promise( (resolve, reject)=>{
	reject("reject","的","参","数");        ////////  结果 "reject undefined undefined undefined" 反映reject只能传递一个参数
	resolve("resolve","的","参数");        //////// 没有执行, 执行了 reject 就不会再执行 resove
}).then(
	(v0,v1,v2) => console.log(v0,v1,v2,"从then的第一个函数参数执行的输出")
	//,
	//(v0,v1,v2,v3) => console.log(v0,v1,v2,v3,"从then的第二个函数参数执行的输出")        //////// 注释了
).catch(
	(v0,v1,v2,v3) => console.log(v0,v1,v2,v3, "从catch的第一个函数参数执行的输出")        //////// 输出了这条结果
)

从例三看出:

  • rejectresolve一样只能放入一个参数, 多余的参数不会传递下去
  • 如果先执行了reject后, resolve不会执行, 二者只能执行其一
  • 如果then只使用一个参数, reject传递到catch ; 如果then使用两参数, 那么rejectthen的参数2截胡, 不会传递到catch
  • catch的参数一 与 then的参数二 , 二者只能使用其一

















1️⃣ 参考 1

JavaScript Promise 链式调用详解: .then() , .catch() , .finally()

     核心概念图示

graph LR
A[Promise] --> B[.then]
B --> C[.catch]
C --> D[.finally]

     1. .then() :处理成功/失败状态 作用:处理 Promise 的 fulfilled 或 rejected 状态
语法

promise.then(
  onFulfilled,  // (value) => { ... }  成功回调
  onRejected    // (error) => { ... }  可选失败回调
);

特性

  • 返回新 Promise 对象,支持链式调用
  • 回调返回值决定新 Promise 状态:
    .then(value => {
      return 42;            // → Promise.resolve(42)
      return Promise.reject(); // → 拒绝状态
      throw new Error();    // → 拒绝状态
    })
    
  • 若省略 onRejected,错误会向下传递

示例

fetchData()
  .then(
    data => console.log("成功:", data), 
    err => console.warn("初级错误:", err) // 仅捕获当前错误
  )

     2. .catch() :专业错误处理 作用:专门处理 rejected 状态(相当于 .then(null, onRejected)
语法

promise.catch(onRejected); // (error) => { ... }

关键特性

  • 捕获链中所有未处理的错误
  • 返回新 Promise,可继续链式操作
  • 能修复错误状态:
    .catch(err => {
      console.error(err);
      return backupData; // 返回新值 → 转为 resolved 状态
    })
    

错误传递机制

fetchData()
  .then(step1)     // 出错 → 跳过后续 then
  .then(step2)     // 
  .catch(err => {  // ← 错误在此被捕获
    console.error("全局捕获:", err); 
  });

     3. .finally() :终极清理操作 作用:无论成功/失败都执行(类似 try/catch/finally
语法

promise.finally(onFinally); // () => { ... }

核心特性

  1. 不接收参数:无法知道 Promise 最终状态
  2. 不影响结果:传递原始 Promise 的状态/值
    Promise.resolve(2)
      .finally(() => {})  // 仍返回 2
      .then(v => console.log(v)) // 输出 2
    
    Promise.reject("err")
      .finally(() => {})  // 仍抛出 "err"
      .catch(e => console.log(e)) // 输出 "err"
    
  3. 适合执行清理操作
    let loading = true;
    
    fetchData()
      .then(data => render(data))
      .catch(err => showError(err))
      .finally(() => {
        loading = false; // 无论成败都关闭加载指示器
      });
    

     4. 完整执行流程

function demo() {
  return Promise.resolve(10) // 初始值
    .then(v => {
      console.log("Step 1:", v); // 10
      return v * 2; 
    })
    .then(v => {
      console.log("Step 2:", v); // 20
      throw new Error("出错了!"); // 模拟错误
    })
    .catch(err => {
      console.error("捕获错误:", err.message); // "出错了!"
      return 0; // 修复错误状态
    })
    .finally(() => {
      console.log("清理资源..."); // 始终执行
    });
}

// 执行结果:
// Step 1: 10
// Step 2: 20
// 捕获错误: 出错了!
// 清理资源...
// 最终返回值: 0

     5. 特殊场景处理 场景 1:.finally() 中的异步操作

promise
  .finally(async () => {
    await cleanUp(); // 需等待异步清理完成
  })
  .then(data => {
    // 需等待 finally 中的 Promise 完成
  });

场景 2:.finally() 抛出错误

Promise.resolve(1)
  .finally(() => {
    throw new Error("finally 出错"); // 覆盖原始状态
  })
  .catch(err => {
    console.log(err.message); // "finally 出错"
  });

场景 3:值穿透现象

Promise.resolve("原始值")
  .finally(() => {}) // 无返回值
  .then(v => console.log(v)); // "原始值" (值穿透)

     6. 最佳实践指南

  1. 错误处理

    // ✅ 推荐:统一用 catch 结尾
    fetchData()
      .then(process)
      .catch(handleError);
    
    // ❌ 避免:混用 then 的第二个参数
    fetchData().then(process, handleError); // 无法捕获 process 中的错误
    
  2. 资源清理

    let resource;
    getResource()
      .then(res => resource = res)
      .finally(() => {
        if (resource) resource.release(); // 安全释放资源
      });
    
  3. 链式中断

    fetchData()
      .then(data => {
        if (!data.valid) throw new Error("无效数据");
        return data;
      })
      .catch(err => { // 中断后续 then
        console.error(err);
        return null; 
      });
    
  4. 组合使用

    async function loadPage() {
      showLoader();
      try {
        const data = await fetchData();
        renderContent(data);
      } catch (err) {
        showError(err);
      } finally { // 替代 .finally()
        hideLoader();
      }
    }
    

执行规则总结

方法接收参数返回值决定因素状态传递规则
.then()值/错误回调返回值可改变后续状态
.catch()错误对象回调返回值可修复为 resolved 状态
.finally()无参数忽略返回值保持原始状态
flowchart TD
    A[Promise] --> B[.then]
    B -- 成功 --> C[执行 onFulfilled]
    B -- 失败 --> D[执行 onRejected 或传递]
    C --> E[新 Promise]
    D --> F[.catch 处理]
    F --> G[新 Promise]
    E --> H[.finally]
    G --> H
    H --> I[执行清理]
    I --> J[传递原始值/状态]

















2️⃣ 参考 2

Promise().then().catch().finally() 详解

在 JavaScript 的异步编程中,Promise 提供了强大的链式调用能力,而 then()catch()finally() 构成了 Promise 链式调用的核心方法。下面我将详细解析这个完整的链式结构。

完整链式结构

new Promise((resolve, reject) => {
  // 执行异步操作
})
.then(result => {
  // 处理成功结果
})
.catch(error => {
  // 处理错误
})
.finally(() => {
  // 最终执行的操作
});

核心方法详解

     1. Promise 构造函数

new Promise(executor)
  • executor: 接收两个参数 (resolve, reject) => {}
  • 作用:创建新的 Promise 对象,执行异步操作
  • 状态转换
    • resolve(value) → 状态变为 fulfilled
    • reject(reason) → 状态变为 rejected
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    const success = Math.random() > 0.5;
    success ? resolve("操作成功!") : reject("操作失败!");
  }, 1000);
});

     2. then() 方法

promise.then(onFulfilled, onRejected?)
  • onFulfilled:当 Promise 状态变为 fulfilled 时调用
  • onRejected(可选):当 Promise 状态变为 rejected 时调用
  • 返回:新的 Promise 对象,支持链式调用
promise
  .then(
    result => {
      console.log("成功:", result);
      return "新数据"; // 返回新值
    },
    error => {
      console.warn("失败:", error);
      return "备用数据"; // 错误恢复
    }
  );

     3. catch() 方法

promise.catch(onRejected)
  • onRejected:处理 rejected 状态
  • 本质catch(onRejected) 等同于 then(null, onRejected)
  • 优势:捕获链中所有未处理的错误
promise
  .then(result => {
    console.log(result);
    throw new Error("then 中的错误"); // 抛出新错误
  })
  .catch(error => {
    console.error("捕获所有错误:", error);
    return "恢复的数据"; // 错误恢复
  });

     4. finally() 方法

promise.finally(onFinally)
  • onFinally:无参数回调,无论成功/失败都会执行
  • 特点
    • 不接收任何参数(不知道 Promise 的结果)
    • 不改变 Promise 的最终结果
  • 使用场景:清理资源、关闭连接、隐藏加载动画等
promise
  .then(result => console.log(result))
  .catch(error => console.error(error))
  .finally(() => {
    console.log("操作完成,清理资源");
    hideLoadingSpinner();
  });

执行流程详解

     完整流程示例

let step = 1;

function logStep(message) {
  console.log(`步骤 ${step++}: ${message}`);
}

new Promise((resolve, reject) => {
  logStep("Promise 开始执行");
  setTimeout(() => {
    Math.random() > 0.5 ? resolve("成功数据") : reject("错误原因");
  }, 1000);
})
.then(result => {
  logStep(`then 接收结果: ${result}`);
  return `处理后的 ${result}`;
})
.catch(error => {
  logStep(`catch 捕获错误: ${error}`);
  return "恢复数据";
})
.finally(() => {
  logStep("finally 执行清理");
})
.then(finalResult => {
  logStep(`最终结果: ${finalResult}`);
});

     可能输出结果

         成功情况:

步骤 1: Promise 开始执行
步骤 2: then 接收结果: 成功数据
步骤 3: finally 执行清理
步骤 4: 最终结果: 处理后的 成功数据

         失败情况:

步骤 1: Promise 开始执行
步骤 2: catch 捕获错误: 错误原因
步骤 3: finally 执行清理
步骤 4: 最终结果: 恢复数据

关键特性详解

     1. 值传递与状态传递

// 值传递
Promise.resolve("初始值")
  .then(val => val + " 第一次处理")
  .then(val => val + " 第二次处理")
  .then(console.log); // 初始值 第一次处理 第二次处理

// 状态传递
Promise.reject("初始错误")
  .catch(err => {
    console.error(err); // 初始错误
    return "新值"; // 返回解决状态的Promise
  })
  .then(console.log); // 新值

     2. 错误处理机制

Promise.resolve()
  .then(() => {
    throw new Error("错误1");
  })
  .then(() => {
    console.log("这步不会执行");
  })
  .catch(err => {
    console.error("捕获:", err.message); // 捕获: 错误1
    throw new Error("错误2"); // 重新抛出错误
  })
  .catch(err => {
    console.error("再次捕获:", err.message); // 再次捕获: 错误2
  });

     3. finally 的特殊行为

// finally 不改变结果值
Promise.resolve("原始值")
  .finally(() => {})
  .then(console.log); // 原始值

Promise.reject("原始错误")
  .finally(() => {})
  .catch(console.error); // 原始错误

// finally 返回Promise会改变结果
Promise.resolve("原始值")
  .finally(() => {
    return Promise.resolve("新值"); // 会被忽略
  })
  .then(console.log); // 原始值

Promise.resolve("原始值")
  .finally(() => {
    return Promise.reject("finally错误"); // 会覆盖原始结果
  })
  .catch(console.error); // finally错误

实际应用场景

     1. API 请求处理

function fetchUserData(userId) {
  showLoadingSpinner();
  
  return fetch(`/api/users/${userId}`)
    .then(response => {
      if (!response.ok) throw new Error('API请求失败');
      return response.json();
    })
    .then(user => {
      console.log("用户数据:", user);
      return user;
    })
    .catch(error => {
      console.error("获取用户数据失败:", error);
      return getCachedUserData(userId); // 尝试获取缓存
    })
    .finally(() => {
      hideLoadingSpinner();
      logAnalyticsEvent('user_data_fetch_completed');
    });
}

     2. 数据库事务处理

function saveUserProfile(user) {
  let dbConnection;
  
  return openDatabase()
    .then(connection => {
      dbConnection = connection;
      return connection.beginTransaction();
    })
    .then(() => validateUserData(user))
    .then(() => dbConnection.save(user))
    .then(() => dbConnection.commit())
    .catch(error => {
      console.error("保存失败:", error);
      if (dbConnection) return dbConnection.rollback();
    })
    .finally(() => {
      if (dbConnection) dbConnection.close();
      console.log("数据库连接已关闭");
    });
}

     3. 动画序列控制

function animateElement(element) {
  return new Promise(resolve => {
    element.classList.add('animating');
    setTimeout(resolve, 1000);
  })
    .then(() => {
      element.style.transform = 'translateX(200px)';
      return wait(500);
    })
    .then(() => {
      element.style.backgroundColor = 'blue';
      return wait(500);
    })
    .catch(error => {
      console.error("动画出错:", error);
    })
    .finally(() => {
      element.classList.remove('animating');
      console.log("动画完成");
    });
}

function wait(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

最佳实践指南

  1. 优先使用 async/await 但理解 Promise

    async function getUserData() {
      try {
        const data = await fetchData();
        const processed = await processData(data);
        return processed;
      } catch (error) {
        console.error(error);
        return fallbackData();
      } finally {
        cleanUp();
      }
    }
    
  2. 避免嵌套 Promise

    // 不推荐
    fetchData().then(data => {
      processData(data).then(result => {
        saveResult(result).then(() => {
          console.log("完成");
        });
      });
    });
    
    // 推荐
    fetchData()
      .then(processData)
      .then(saveResult)
      .then(() => console.log("完成"));
    
  3. 始终添加错误处理

    // 危险:未处理的Promise拒绝
    fetchData();
    
    // 安全
    fetchData()
      .then(handleData)
      .catch(handleError);
    
  4. 合理使用 finally 进行清理

    let resource;
    
    acquireResource()
      .then(res => {
        resource = res;
        return useResource(resource);
      })
      .then(result => processResult(result))
      .catch(handleError)
      .finally(() => {
        if (resource) releaseResource(resource);
      });
    
  5. 避免在 finally 中返回值

    // 可能引起混淆
    Promise.resolve('原始值')
      .finally(() => '新值') // 这个值会被忽略
      .then(console.log); // 输出: 原始值
    

常见误区与解决方案

     1. 忘记返回 Promise

// 错误
fetchData()
  .then(data => {
    processData(data); // 忘记return
  })
  .then(result => {
    // result 是 undefined
  });

// 正确
fetchData()
  .then(data => processData(data)) // 返回Promise
  .then(result => console.log(result));

     2. 错误处理位置不当

// 错误:无法捕获fetchData中的错误
fetchData()
  .then(data => {
    processData(data);
  }, handleError); // 只能处理fetchData错误

// 正确
fetchData()
  .then(data => processData(data))
  .catch(handleError); // 捕获所有错误

     3. finally 中的错误处理

// finally 中的错误需要单独处理
somePromise
  .finally(() => {
    throw new Error("清理错误");
  })
  .catch(error => console.error("捕获finally错误:", error));

总结

Promise 链式调用 Promise().then().catch().finally() 提供了强大的异步控制能力:

  1. Promise 构造函数:创建异步操作
  2. then():处理成功状态和转换值
  3. catch():捕获链中所有错误
  4. finally():执行必要的清理操作

关键要点:

  • 每个方法都返回新的 Promise,支持链式调用
  • 错误沿链向下传播直到被 catch 捕获
  • finally 不改变最终结果值
  • 合理组合使用可创建健壮的异步流程

掌握这些方法的使用方式和交互行为,对于编写可维护、可读性高的异步 JavaScript 代码至关重要。

















3️⃣ 参考 3

以下是关于 JavaScript 中 Promise().then().catch().finally() 的详细解析,通过代码示例和执行流程说明其工作原理:


一、Promise 链式调用核心机制

new Promise((resolve, reject) => {
  // 异步操作(如 API 请求)
  setTimeout(() => resolve("Success"), 1000);
})
  .then(
    (value) => { /* 处理成功 */ },
    (error) => { /* 处理失败 */ }
  )
  .catch((error) => { /* 捕获链中所有错误 */ })
  .finally(() => { /* 无论成功失败都会执行 */ });

二、方法详解与执行顺序

     1. .then() 方法

  • 作用:注册 Promise 成功(Fulfilled)和失败(Rejected)的回调函数。
  • 返回值:返回 新的 Promise,允许链式调用。
  • 参数
    • onFulfilled:成功回调(可选)
    • onRejected:失败回调(可选)
promise
  .then(
    (value) => {
      console.log("成功:", value);
      return value + "!"; // 返回值传递给下一个.then()
    },
    (error) => {
      console.error("失败:", error);
      throw new Error("处理失败"); // 抛出错误触发后续.catch()
    }
  )
  .then((newValue) => {
    console.log("链式传递:", newValue); // 输出 "成功: Success!"
  });

     2. .catch() 方法

  • 作用:捕获 Promise 链中任何位置抛出的错误。
  • 等价于.then(null, onRejected),但更推荐使用 .catch()
  • 错误冒泡:如果前面的 .then() 未处理错误,错误会一直传递到最近的 .catch()
promise
  .then((value) => {
    throw new Error("Oops!"); // 抛出错误
  })
  .catch((error) => {
    console.error("捕获错误:", error.message); // 输出 "Oops!"
    return "Recovered"; // 恢复链式调用
  })
  .then((value) => {
    console.log("继续执行:", value); // 输出 "Recovered"
  });

     3. .finally() 方法

  • 作用:无论 Promise 成功或失败,都会执行(如清理资源)。
  • 返回值:返回的 Promise 会继承原 Promise 的状态和值,除非内部抛出错误。
let isLoading = true;

promise
  .then((value) => {
    console.log("成功:", value);
  })
  .catch((error) => {
    console.error("失败:", error);
  })
  .finally(() => {
    isLoading = false; // 关闭加载状态
    console.log("请求结束"); // 无论成功失败都会执行
  });

三、执行顺序与错误冒泡      示例 1:正常流程

new Promise((resolve) => resolve(1))
  .then((v) => {
    console.log(v); // 1
    return v + 1;   // 返回 2
  })
  .then((v) => {
    console.log(v); // 2
  })
  .finally(() => {
    console.log("Done"); // 最后执行
  });

// 输出顺序:1 → 2 → Done

     示例 2:错误处理

new Promise((resolve, reject) => reject("Error"))
  .then((v) => console.log(v)) // 跳过
  .catch((e) => {
    console.error("捕获:", e); // 输出 "Error"
    return "Recovered";
  })
  .then((v) => console.log(v)); // 输出 "Recovered"

     示例 3:finally 覆盖错误

new Promise((resolve, reject) => reject("Error"))
  .finally(() => {
    throw new Error("Final Error"); // 覆盖原错误
  })
  .catch((e) => {
    console.error("最终错误:", e.message); // 输出 "Final Error"
  });

四、关键规则总结

  1. 链式传递:每个 .then() 的返回值会作为下一个 .then() 的输入。
  2. 错误冒泡:未处理的错误会沿链向下传递,直到遇到 .catch()
  3. finally 特性
    • 不改变原 Promise 的结果(除非内部抛出错误)。
    • 适合执行清理操作(如关闭弹窗、停止加载动画)。
  4. 返回值处理
    • 返回非 Promise 值:自动包装为 Promise.resolve(value)
    • 返回 Promise:等待其解决后再继续链式调用。

五、最佳实践

  1. 统一错误处理:在链式调用末尾使用 .catch() 集中处理错误。
  2. 避免嵌套:通过链式调用替代回调地狱。
  3. 资源清理:使用 .finally() 释放资源(如关闭文件、网络连接)。
// 推荐写法
fetchData()
  .then(processData)
  .then(displayData)
  .catch(handleError)
  .finally(cleanup);

通过理解这些机制,可以更高效地编写异步代码,避免常见陷阱。如果需要进一步探讨具体场景,请随时提问!

















4️⃣ 参考 4

以下是关于 JavaScript 中 Promise().then().catch().finally() 的详细解析,涵盖其核心概念、执行顺序、错误处理及实际应用场景。


1. Promise 的基本概念 Promise 是 JavaScript 处理异步操作的核心对象,它有三种状态:

  • pending(进行中):初始状态,操作未完成。
  • fulfilled(已成功):操作成功,返回结果。
  • rejected(已失败):操作失败,抛出错误。

一旦状态从 pending 变为 fulfilledrejected,状态不可逆。


2. 核心方法详解      2.1 .then() :处理成功结果

  • 作用:当 Promise 状态变为 fulfilled 时执行回调。
  • 参数
    • onFulfilled:成功回调,接收 resolve 的值。
    • onRejected(可选):失败回调,接收 reject 的错误。
  • 返回值:返回一个新的 Promise,支持链式调用。

示例

new Promise((resolve, reject) => {
  resolve("成功");
})
  .then(result => {
    console.log("成功:", result); // 输出 "成功: 成功"
    return result + " 处理后";
  })
  .then(newResult => {
    console.log("链式调用:", newResult); // 输出 "链式调用: 成功 处理后"
  });

     2.2 .catch() :捕获错误

  • 作用:捕获 Promise 链中的错误(rejected 状态)。
  • 参数
    • onRejected:错误回调,接收错误原因。
  • 返回值:返回一个新的 Promise,支持链式调用。

示例

new Promise((resolve, reject) => {
  reject("失败");
})
  .then(result => {
    console.log("成功:", result); // 不会执行
  })
  .catch(error => {
    console.error("失败:", error); // 输出 "失败: 失败"
  });

     2.3 .finally() :无论成功/失败都执行

  • 作用:无论 Promise 状态如何,最终都会执行的回调,常用于清理资源。
  • 参数:无参数。
  • 返回值:返回一个新的 Promise,状态由前一个方法决定。

示例

new Promise((resolve, reject) => {
  resolve("成功");
})
  .then(result => {
    console.log("成功:", result);
  })
  .catch(error => {
    console.error("失败:", error);
  })
  .finally(() => {
    console.log("无论成功或失败,都会执行"); // 输出 "无论成功或失败,都会执行"
  });

3. 执行顺序与错误处理      3.1 正常流程

Promise.resolve(1)
  .then(value => {
    console.log("Step 1:", value); // Step 1: 1
    return value + 1;
  })
  .then(value => {
    console.log("Step 2:", value); // Step 2: 2
    return value + 1;
  })
  .finally(() => {
    console.log("Finally"); // Finally
  });

     3.2 错误流程

Promise.resolve(1)
  .then(value => {
    console.log("Step 1:", value); // Step 1: 1
    throw new Error("Error in then");
  })
  .catch(error => {
    console.error("Caught:", error.message); // Caught: Error in then
  })
  .finally(() => {
    console.log("Finally"); // Finally
  });

     3.3 错误传播

  • 如果 .catch() 中再次抛出错误,.finally() 仍会执行,但链的状态变为 rejected
Promise.resolve(1)
  .then(value => {
    throw new Error("First error");
  })
  .catch(error => {
    console.error("First catch:", error.message);
    throw new Error("Second error");
  })
  .finally(() => {
    console.log("Finally"); // Finally
  });

4. 链式调用的注意事项      4.1 返回值传递

  • 返回普通值:下一个 .then() 接收到该值。
  • 返回 Promise:下一个 .then() 会等待该 Promise 完成后再执行。
Promise.resolve(1)
  .then(value => {
    return new Promise(resolve => {
      setTimeout(() => resolve(value + 1), 1000);
    });
  })
  .then(value => {
    console.log("延迟处理:", value); // 延迟1秒后输出 "延迟处理: 2"
  });

     4.2 避免链式调用断裂

  • 如果 .then() 忘记返回值,后续的 .then() 将接收到 undefined
Promise.resolve(1)
  .then(value => {
    console.log("Step 1:", value); // Step 1: 1
    // 忘记返回值
  })
  .then(value => {
    console.log("Step 2:", value); // Step 2: undefined
  });

5. 实际应用场景      5.1 数据加载与处理

fetchData()
  .then(data => processData(data))
  .then(result => console.log("处理结果:", result))
  .catch(error => console.error("全局错误:", error));

     5.2 资源清理

openFile()
  .then(file => processFile(file))
  .catch(error => console.error("处理文件失败:", error))
  .finally(() => closeFile());

     5.3 并行执行多个异步操作

Promise.all([
  fetch("https://api.example.com/data1"),
  fetch("https://api.example.com/data2"),
])
  .then(results => {
    console.log("所有数据加载完成:", results);
  })
  .catch(error => {
    console.error("至少一个请求失败:", error);
  });

6. 与 async/await 的对比

  • .then():适合链式调用,但嵌套较深时可读性较差。
  • async/await:语法更接近同步代码,推荐用于复杂异步流程。
// 使用 async/await
async function run() {
  try {
    const result = await new Promise(resolve => setTimeout(() => resolve("成功"), 1000));
    console.log("结果:", result);
  } catch (error) {
    console.error("错误:", error);
  } finally {
    console.log("清理资源");
  }
}

7. 总结

方法作用执行时机返回值类型
.then()处理成功结果,支持链式调用Promise 状态为 fulfilled新的 Promise
.catch()捕获错误,处理异常Promise 状态为 rejected新的 Promise
.finally()无论成功/失败都会执行,用于清理资源Promise 状态为 settled新的 Promise

最佳实践

  1. 错误处理优先:将 .catch() 放在链式调用的末尾,确保捕获所有错误。
  2. 链式调用完整性:确保每个 .then() 返回值,避免链断裂。
  3. 合理使用 .finally():用于清理资源或执行必须的操作,如关闭加载动画。

通过合理使用 Promise.then().catch().finally(),可以显著提升异步代码的可读性和健壮性。

















5️⃣ 参考 5

Promise().then().catch().finally() 是 JavaScript 中处理异步操作的完整链式调用模式,结合了 Promise 的核心方法,能够优雅地处理异步操作的成功、失败和最终清理逻辑。下面详细解析这个组合的用法和特性:

一、整体结构与作用

new Promise((resolve, reject) => {
  // 异步操作逻辑(如网络请求、定时器)
})
.then(onFulfilled)       // 处理成功结果
.catch(onRejected)       // 捕获所有错误
.finally(onFinally);     // 执行最终操作(无论成功/失败)

这四个部分分工明确:

  • new Promise(...):封装异步操作
  • .then():处理异步操作成功的结果
  • .catch():捕获整个链中所有可能的错误
  • .finally():无论异步操作成功或失败,最终必定执行的逻辑

二、各方法详解与协同工作

     1. new Promise(executor)

  • 作用:创建一个 Promise 实例,封装异步操作。
  • 参数executor 函数((resolve, reject) => {}),立即执行。
    • resolve(value):将状态改为 fulfilled,传递成功结果 value
    • reject(error):将状态改为 rejected,传递错误信息 error
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    const success = Math.random() > 0.5;
    success ? resolve("数据加载完成") : reject(new Error("加载失败"));
  }, 1000);
});

     2. .then(onFulfilled)

  • 作用:注册 fulfilled 状态的回调(处理成功结果)。
  • 返回值:新的 Promise 实例(支持链式调用)。
  • 特性
    • 回调返回的值会作为下一个 Promise 的结果
    • 若回调中抛出错误,会触发后续的 catch
promise
  .then((result) => {
    console.log("成功:", result); // 输出"数据加载完成"(若成功)
    return result + ",已处理"; // 传递给下一个then(若有)
  })

     3. .catch(onRejected)

  • 作用:捕获整个链中所有 rejected 状态的错误,包括:
    • Promise 内部调用 reject() 的错误
    • then 回调中抛出的异常(throw new Error(...)
    • 异步操作中发生的错误
  • 本质then(null, onRejected) 的语法糖,返回新的 Promise。
  .catch((error) => {
    console.log("错误:", error.message); // 捕获所有错误(如"加载失败")
    // 可选:处理错误后返回新值,让后续then继续执行
    return "错误已处理,继续执行";
  })

     4. .finally(onFinally)

  • 作用:指定无论 Promise 状态如何(成功/失败)都必须执行的逻辑(如清理资源、隐藏加载动画)。
  • 特性
    • 不接收任何参数(无法获取前面的结果或错误)
    • 返回的 Promise 会传递前面的结果/错误(不改变原有链的状态)
  .finally(() => {
    console.log("操作结束,清理资源"); // 必定执行
  });

三、完整执行流程示例

// 模拟一个异步操作(加载数据)
new Promise((resolve, reject) => {
  console.log("开始加载数据...");
  setTimeout(() => {
    const success = Math.random() > 0.5;
    if (success) {
      resolve({ id: 1, name: "示例数据" }); // 成功:返回数据
    } else {
      reject(new Error("网络超时")); // 失败:抛出错误
    }
  }, 1000);
})
.then((data) => {
  console.log("数据加载成功:", data);
  if (!data.name) {
    throw new Error("数据格式错误"); // 主动抛出新错误
  }
  return data.name; // 传递用户名给下一个then
})
.then((name) => {
  console.log("处理后的用户名:", name);
})
.catch((error) => {
  console.log("捕获到错误:", error.message); // 处理所有错误
})
.finally(() => {
  console.log("加载流程结束,关闭加载动画"); // 最终清理
});

两种执行路径

  1. 成功路径

    开始加载数据...
    数据加载成功:{id: 1, name: "示例数据"}
    处理后的用户名:示例数据
    加载流程结束,关闭加载动画
    
  2. 失败路径(如网络超时):

    开始加载数据...
    捕获到错误:网络超时
    加载流程结束,关闭加载动画
    

四、关键特性总结

  1. 错误冒泡:链中任何位置的错误都会一直传递,直到被 catch 捕获。
  2. 状态穿透finally 不改变 Promise 链的状态,前面的结果/错误会继续传递。
  3. 链式灵活性:每个方法返回新的 Promise,可根据需求无限延长链(如多步数据处理)。
  4. 统一处理catch 集中处理所有错误,finally 集中处理清理逻辑,代码更整洁。

五、常见使用场景

  • 网络请求:加载数据 → 处理数据 → 处理错误 → 隐藏加载状态
  • 文件操作:读取文件 → 解析内容 → 处理异常 → 关闭文件流
  • 表单提交:验证数据 → 提交请求 → 处理响应/错误 → 重置表单

通过 Promise().then().catch().finally() 的组合,能够清晰地分离异步操作的不同阶段逻辑,避免回调嵌套,是现代 JavaScript 异步编程的标准模式。

















6️⃣ 参考 6

下面用「一张图 + 逐行拆解」的方式把
Promise().then().catch().finally()
执行顺序、参数/返回值、使用场景、易错点一次性讲透。
你可以直接收藏当手册。

────────────────

  1. 全貌速记(先背下来) ────────────────
newPromise
   ↓ 落定
.then(onFulfilled, onRejected)   ← 可选
   ↓ 返回新的 Promise
.catch(onRejected)               ← 只能捕获前面抛错
   ↓ 返回新的 Promise
.finally(onFinally)              ← 无论成功失败都会执行
   ↓ 返回新的 Promise

──────────────── 2. 四个方法原型签名 ────────────────

Promise.prototype.then   (onFulfilled?, onRejected?) => Promise
Promise.prototype.catch  (onRejected)               => Promise
Promise.prototype.finally(onFinally)                => Promise

都返回新的 Promise,因此可无限链式。
都不改变原 Promise,原 Promise 一旦落定就不可变。

──────────────── 3. 执行时机 & 参数差异 ────────────────

方法触发条件参数返回值影响新 Promise
thenfulfilled / rejectedvalue / reason取决于 return / throw
catch前面任何 reject / throwreason取决于 return / throw
finally无论 fulfilled/rejected无参透传原状态/值

重点:finally 回调 收不到结果,也不能 return 改变最终状态;
它仅用于“清理”——关闭 loading、释放资源等。

──────────────── 4. 运行顺序 & 微任务 ────────────────

console.log(1);
Promise.resolve('A')
  .then(v => { console.log(2, v); return 'B'; })
  .catch(e => console.log('catch', e))
  .finally(() => console.log(3))
  .then(v => console.log(4, v));
console.log(5);

// 输出顺序:1 → 5 → 2 A → 3 → 4 B

解释:
1 → 5 是同步栈;2/3/4 都是微任务,按注册顺序执行。
finally 不会打断链,只是“路过”执行副作用。

──────────────── 5. 透传演示(finally 不吞结果) ────────────────

Promise.reject('err')
  .catch(r => 'recovered') // 返回普通值 → 链变 fulfilled
  .finally(() => console.log('finally'))
  .then(v => console.log('value:', v)); // value: recovered

──────────────── 6. 经典误区 ──────────────── ① 把 finallycatch

Promise.reject('boom')
  .finally(() => {}) // 不处理错误
  .then(v => console.log('ok?')); // 这里不会触发
// Uncaught (in promise) boom

② 在 finallyreturn Promise.reject()

Promise.resolve(1)
  .finally(() => Promise.reject('oops')) // 会**改变**链为 rejected
  .catch(e => console.log(e));          // oops

规则:finally 默认透传,但你若显式返回 rejected Promise 或 throw,就会覆盖。

──────────────── 7. 实战模板代码 ────────────────

async function loadUser(id) {
  startSpinner();
  return fetch(`/user/${id}`)
    .then(r => r.json())
    .catch(err => {
      console.error(err);
      return { id, name: 'Unknown' }; // 降级
    })
    .finally(() => stopSpinner());
}

──────────────── 8. 记忆口诀 ──────────────── then 处理值、catch 处理错、finally 只打扫。
任何一步 return / throw 都会影响后续,唯独 finally 默认“穿堂过”。

──────────────── 9. 一句话总结 ──────────────── Promise → then → catch → finally 是一条流水线:
then/catch 决定“流”里装什么,finally 只负责“擦桌子”,不碰盘子也不换菜。

















7️⃣ 参考 7

JavaScript Promise 的 then 、 catch 和 finally 方法详解

     1. Promise 核心机制 Promise 是 JavaScript 处理异步操作的对象,包含三种状态:

  • pending:初始状态,操作未完成
  • fulfilled:操作成功完成(调用 resolve
  • rejected:操作失败(调用 reject) 状态转换公式:
    pending{fulfilled(resolve)rejected(reject)\text{pending} \rightarrow \begin{cases} \text{fulfilled} & \text{(resolve)} \\ \text{rejected} & \text{(reject)} \end{cases} 关键特性:状态一旦改变(fulfilledrejected)即不可逆。

     2. ** then() 方法** 作用:处理 Promise 的完成(fulfilled)或拒绝(rejected)状态。

promise.then(
  (value) => { /* 成功处理逻辑 */ },  // 当状态为 fulfilled 时执行
  (error) => { /* 失败处理逻辑 */ }   // 当状态为 rejected 时执行(可选)
);

特点

  • 返回新的 Promise,支持链式调用
  • 若未提供错误回调,错误会向下传递
  • 示例:
    fetchData()
      .then(data => console.log("成功:", data))
      .then(() => console.log("可继续链式调用"));
    

     3. ** catch() 方法** 作用:专门捕获 Promise 链中的错误(rejected 状态)。

promise
  .then(/* ... */)
  .catch(error => { /* 统一错误处理 */ });

特点

  • 本质是 .then(null, errorHandler) 的语法糖
  • 捕获链中任意位置的错误(包括 then 内的异常)
  • 示例:
    fetchData()
      .then(data => { throw new Error("处理失败") })
      .catch(err => console.error("捕获错误:", err)); // 捕获 then 中的异常
    

     4. ** finally() 方法** 作用:无论 Promise 最终状态如何,必定执行的清理逻辑(ES2018 引入)。

promise
  .then(/* ... */)
  .catch(/* ... */)
  .finally(() => { /* 清理逻辑 */ });

特点

  • 不接收任何参数(无法获知最终状态)
  • 不影响 Promise 链的值传递(原值继续传递)
  • 示例:
    let isLoading = true;
    fetchData()
      .then(data => console.log(data))
      .catch(err => console.error(err))
      .finally(() => {
        isLoading = false; // 无论成败都关闭加载状态
        console.log("请求结束");
      });
    

     5. 组合使用示例

function simulateFetch() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      Math.random() > 0.5 
        ? resolve("数据获取成功") 
        : reject(new Error("网络错误"));
    }, 1000);
  });
}

simulateFetch()
  .then(data => {
    console.log("步骤1:", data);
    return data.toUpperCase(); // 传递给下一步
  })
  .then(processedData => {
    console.log("步骤2:", processedData);
  })
  .catch(err => {
    console.error("错误处理:", err.message);
  })
  .finally(() => {
    console.log("清理资源...");
  });

输出可能

步骤1: 数据获取成功
步骤2: 数据获取成功
清理资源...

错误处理: 网络错误
清理资源...

     关键差异总结

方法触发条件接收参数返回值影响
then()成功/失败(可选)valueerror可改变链式值
catch()仅失败error可返回新值恢复
finally()任何状态不影响原值

引用说明:
: finally() 在 ES2018 引入,用于无关状态的清理操作。
: finally() 不改变 Promise 链的值传递逻辑。
: Promise 状态一旦改变即不可逆,需防止二次修改。


















8️⃣ 参考 8

Promise().then().catch().finally() 详解


     一、方法链的核心逻辑

  1. 执行顺序与状态传递

    • 同步代码优先执行Promise 构造函数内的代码立即执行,then/catch/finally 回调通过微任务队列调度。
    • 状态决定执行路径
      • Fulfilled:触发 .then(onFulfilled),跳过 .catch
      • Rejected:触发 .catch(onRejected),跳过后续 .then
      • 无论状态如何.finally 总会执行。
  2. 链式调用的本质

    • 每个方法返回新 Promise,允许连续调用。
    • 示例:
      new Promise((resolve, reject) => {
        resolve("成功");
      })
      .then(result => {
        console.log(result); // 输出:成功
        return "新值";
      })
      .then(newValue => console.log(newValue)) // 输出:新值
      .catch(error => console.error(error))
      .finally(() => console.log("最终执行"));
      

     二、各方法详解

  1. .then(onFulfilled, onRejected)

    • 参数
      • onFulfilled(可选):成功回调,接收前序 Promise 的解决值。
      • onRejected(可选):失败回调,接收前序 Promise 的拒绝原因。
    • 返回值:新 Promise,状态由回调返回值决定:
      • 返回普通值 → 新 Promise 以该值 fulfilled
      • 返回 Promise → 继承其状态。
    • 错误处理:未捕获的错误会冒泡到链尾的 .catch
      Promise.resolve()
        .then(() => { throw new Error("错误") })
        .catch(error => console.error(error.message)); // 输出:错误
      
  2. .catch(onRejected)

    • 等价于.then(null, onRejected)
    • 作用:捕获链中任意位置的错误,支持错误恢复。
    • 示例
      fetch("https://api.example.com/data")
        .then(response => {
          if (!response.ok) throw new Error("请求失败");
          return response.json();
        })
        .catch(error => {
          console.error("捕获错误:", error);
          return { data: "默认值" }; // 恢复流程
        });
      
  3. .finally(onFinally)

    • 特性
      • 无论 Promise 成功或失败均执行。
      • 不接收参数,无法访问结果或错误。
      • 返回的 Promise 继承原状态,但若 onFinally 抛出错误,会覆盖原结果。
    • 使用场景
      • 清理资源(如关闭加载动画)。
      • 日志记录。
    • 示例
      let isLoading = true;
      fetchData()
        .then(data => console.log(data))
        .catch(error => console.error(error))
        .finally(() => {
          isLoading = false; // 无论成功/失败都关闭加载
        });
      

     三、链式调用的高级用法

  1. 错误恢复与降级处理

    fetchPrimarySource()
      .catch(() => fetchBackupSource()) // 主源失败则尝试备用源
      .then(data => processData(data))
      .catch(error => console.error("所有源均失败:", error));
    
  2. 并行任务组合

    Promise.all([fetchUser(), fetchSettings()])
      .then(([user, settings]) => {
        // 同时处理用户和配置数据
      })
      .finally(() => console.log("所有请求完成"));
    
  3. 值传递与转换

    Promise.resolve(1)
      .then(v => v * 2)          // 返回普通值 2
      .then(v => new Promise(resolve => setTimeout(() => resolve(v + 1), 100))) // 返回 Promise
      .then(v => console.log(v)) // 100ms 后输出 3
      .catch(error => console.error(error))
      .finally(() => console.log("流程结束"));
    

     四、底层机制与注意事项

  1. 微任务队列调度

    • .then/.catch/.finally 的回调均放入微任务队列,优先级高于宏任务(如 setTimeout)。
    • 示例:
      console.log("Start");
      Promise.resolve().then(() => console.log("Microtask 1"));
      setTimeout(() => console.log("Macrotask"), 0);
      console.log("End");
      // 输出顺序:Start → End → Microtask 1 → Macrotask
      
  2. 状态不可逆性

    • Promise 状态一旦改变(fulfilled/rejected)不可逆,后续回调仅执行一次。
  3. 常见陷阱

    • 未处理的 Promise:未附加 .catchPromise 拒绝会导致全局错误(如 UnhandledPromiseRejectionWarning)。
    • finally 中的错误:若 finally 回调抛出错误,会覆盖原 Promise 的结果。
      Promise.resolve("成功")
        .finally(() => { throw new Error("finally 错误"); })
        .catch(error => console.error(error.message)); // 输出:finally 错误
      

     五、实际应用示例

  1. 网络请求流程控制

    function fetchData(url) {
      return fetch(url)
        .then(response => {
          if (!response.ok) throw new Error("HTTP错误");
          return response.json();
        })
        .catch(error => {
          console.error("请求失败:", error);
          return { data: null }; // 返回默认值继续流程
        })
        .finally(() => console.log("请求结束"));
    }
    
  2. 异步资源管理

    function withResource(operation) {
      let resource = acquireResource();
      return operation(resource)
        .finally(() => releaseResource(resource)); // 确保资源释放
    }
    

总结

  • .then:处理成功/失败逻辑,支持链式调用和值传递。
  • .catch:统一错误处理,支持错误恢复。
  • .finally:清理与收尾操作,增强代码健壮性。
  • 最佳实践
    • 始终在链尾添加 .catch 避免未处理错误。
    • 使用 .finally 管理资源释放和状态重置。
    • 合理设计链式结构,避免过度嵌套。

















9️⃣ 参考 9

在 JavaScript 异步编程中,Promise 链式调用的 thencatchfinally 方法构成了完整的异步控制体系。以下是它们的工作规则详解:


一、方法特性对比

方法执行条件接收参数返回值影响核心作用
.then()Promise 成功/失败成功值或错误决定下一个 Promise主流程控制
.catch()Promise 失败错误对象可恢复错误状态错误边界处理
.finally()任何状态变化无参数不影响最终结果清理操作(如关闭连接)

二、执行流程示意图

Promise
  .then(() => { /* 步骤1 */ })
  .catch(err => { /* 错误处理 */ })
  .then(() => { /* 步骤2 */ })
  .finally(() => { /* 最终清理 */ });

流程解析

  1. 若步骤1成功 → 执行步骤2 → 执行 finally
  2. 若步骤1失败 → 执行 catch → 执行步骤2 → 执行 finally
  3. 若步骤2中抛出新错误 → 跳过后续 then → 执行 finally

三、 catch 的精确捕获范围

     1. 基础定位

// 等效关系式
promise.catch(onRejected) 
// ≡ 
promise.then(undefined, onRejected)

     2. 作用域限定案例

Promise.resolve()
  .then(() => { throw new Error('错误1') })
  .catch(err => { console.log('捕获:', err.message) }) // 捕获: 错误1
  .then(() => { throw new Error('错误2') }) 
  .catch(err => { console.log('捕获:', err.message) }); // 捕获: 错误2

     3. 穿透效应

Promise.reject(new Error('源错误'))
  .then(v => v) // 跳过成功回调
  .catch(err => { 
    console.log(err.message); // 输出 "源错误"
    return '恢复值'; 
  })
  .then(v => console.log(v)); // 输出 "恢复值"

四、 finally 的特殊行为

     1. 始终执行特性

function testFinally() {
  return Promise.resolve('数据')
    .then(v => { throw new Error('测试错误') })
    .finally(() => console.log('资源已释放'));
}

testFinally().catch(err => console.log(err.message)); 
// 输出顺序: 
// 资源已释放 
// 测试错误

     2. 值传递规则

Promise.resolve(1)
  .finally(() => {})          // 输出 1
  .then(v => console.log(v));

Promise.resolve(2)
  .finally(() => 100)        // 输出 2(finally返回值被忽略)
  .then(v => console.log(v));

Promise.resolve(3)
  .finally(() => Promise.resolve(200))  // 输出 3(仍然忽略)
  .then(v => console.log(v));

     3. 异常阻断

Promise.resolve()
  .finally(() => { throw new Error('finally出错') }) // 抛出错误
  .catch(err => console.log(err.message)); // 输出 "finally出错"

五、复合操作最佳实践

     1. 标准业务流

fetchData()
  .then(data => validate(data)) // 数据校验
  .then(data => process(data))  // 数据处理
  .catch(err => {               // 统一错误处理
    console.error('处理失败:', err);
    return recoverData();       // 返回降级数据
  })
  .finally(() => {              // 释放资源
    closeDatabaseConnection();
    clearLoadingState();
  });

     2. 并行业务流控制

// 并行操作 + 最终清理
Promise.all([task1(), task2(), task3()])
  .then(results => mergeResults(results))
  .catch(err => logError(err))
  .finally(() => sendAnalyticsReport());

六、常见反模式及修复

     1. 冗余嵌套

// 错误写法 ❌
loadData().then(data => {
  processData(data).then(result => {
    saveResult(result).then(() => {
      console.log('完成');
    }).catch(err => console.log(err));
  }).catch(err => console.log(err));
}).catch(err => console.log(err));

// 正确写法 ✅
loadData()
  .then(data => processData(data))
  .then(result => saveResult(result))
  .then(() => console.log('完成'))
  .catch(err => console.log(err));

     2. finally 误用返回值

// 错误示范 ❌
function getData() {
  return fetchData()
    .finally(() => { return '降级数据'; });
}

getData().then(data => console.log(data)); // 实际不会收到 '降级数据'

// 正确修复 ✅
function getData() {
  return fetchData()
    .catch(() => '降级数据');
}

掌握这些核心规则后,你可以:

  • 构建清晰的异步操作流水线
  • 精确控制错误传播路径
  • 安全执行必要的清理操作
  • 避免大部分 Promise 常见陷阱

是否需结合具体场景进一步说明某个方法的特殊用法?

















🔟 参考 10

以下是针对 JavaScript 中 Promise 链式调用 .then().catch().finally() 的超详细解析:


一、核心概念速览

方法触发时机功能描述返回值类型
.then()Promise 变为 fulfilled 状态时处理成功结果 / 转换结果类型新 Promise
.catch()Promise 变为 rejected 状态时 / 前序 .then() 抛出异常时捕获失败原因 / 统一错误处理新 Promise
.finally()Promise 状态已定(fulfilled/rejected),无论成败收尾操作(如清理资源、关闭加载指示器)新 Promise

二、逐层解析与关键规则      ✅ 1. .then(onFulfilled?, onRejected?)           基础用法

promise.then(
  value => { /* 成功回调 */ },      // 可选:接收 fulfilled 的值
  reason => { /* 失败回调 */ }     // 可选:等同于 .catch()
);

         ⚠️ 关键规则:

  • 穿透机制:若回调函数显式返回一个值,该值会成为新 Promise 的 value;若未返回或返回 undefined,新 Promise 的 valueundefined
  • 错误冒泡:若回调函数内部抛出异常,新 Promise 将立即变为 rejected,并携带该异常作为原因。
  • 跳过承诺期.then() 返回的新 Promise 处于等待状态(pending),直到当前回调完成。

          示例:

Promise.resolve(2)
  .then(v => v * 2)               // 返回 4 → 新 Promise
  .then(v => v + 3)               // 返回 7 → 新 Promise
  .then(v => console.log(v));      // 输出 7

     ❌ 2. .catch(onRejected?)           两种触发场景:

  1. 主动拒绝:原 Promise 调用 reject()
  2. 隐式拒绝:前序 .then() 回调中抛出异常。

         ⚠️ 常见误区:

  • 并非只捕获初始错误:它能捕获整条链中所有未被处理的错误。
  • 可省略前面的 .then():直接附加到任何 Promise 后,专门处理拒绝路径。

          示例:

Promise.reject(new Error("原始错误"))
  .catch(err => {
    console.error("首次捕获:", err.message); // 输出 "原始错误"
    throw new Error("放大后的错误");         // 重新抛出新错误
  })
  .catch(err => console.error("最终捕获:", err.message)); // 输出 "放大后的错误"

      3. .finally(callback)           独特特性:

  • 无条件执行:无论 Promise 最终是 fulfilled 还是 rejected,只要状态已定,必然执行。
  • 不支持参数渗透:回调函数不会接收任何参数(既不是成功值也不是失败原因)。
  • 常用于收尾操作:关闭加载动画、释放锁、删除临时文件等。

          示例:

function fetchData() {
  console.log("开始请求...");
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const success = Math.random() > 0.5;
      if (success) resolve("数据到达");
      else reject(new Error("请求超时"));
    }, 1000);
  });
}

fetchData()
  .then(data => console.log("成功:", data))
  .catch(err => console.error("失败:", err.message))
  .finally(() => console.log("请求结束")); // 无论成败均执行

输出可能性之一

开始请求...
成功: 数据到达
请求结束

或:

开始请求...
失败: 请求超时
请求结束

三、执行流程图解

graph TD
    A[起始 Promise] --> B{状态判断}
    B -- Fulfilled --> C["执行 .then() 成功回调"]
    B -- Rejected --> D["执行 .catch() 失败回调"]
    C & D --> E[生成新 Promise]
    E --> F{"是否还有后续 .then()/.catch()/.finally()?"}
    F -- 是 --> G[继续处理下一个处理器]
    F -- 否 --> H["执行 .finally()"]
    H --> I[终止]

四、典型应用场景      ‍ 场景 1:网络请求标准化处理

fetch("/api/user")
  .then(response => {
    if (!response.ok) throw new Error("HTTP 错误 " + response.status);
    return response.json();
  })
  .then(user => updateUI(user))
  .catch(error => showErrorNotification(error))
  .finally(() => hideLoadingSpinner());

     ️ 场景 2:异步操作收尾管理

const dbConnection = openDatabase();
dbConnection
  .query("SELECT * FROM orders")
  .then(processOrders)
  .catch(logDatabaseError)
  .finally(() => dbConnection.close()); // 确保关闭连接

五、高频陷阱警示

陷阱症状解决方案
忽略 .catch()未捕获的错误导致程序崩溃始终添加 .catch() 或全局监听器
.finally() 中依赖参数误以为能拿到成功/失败的具体值.finally() 回调无参数
过度使用嵌套 .then()降低可读性拆分成独立函数
混淆 .then() 的返回值误认为修改了原 Promise 的值每个 .then() 返回新 Promise

六、进阶技巧

  1. 跨步值传递
    Promise.resolve(1)
      .then(v => v + 1)   // 2
      .then(v => v * 2)   // 4
      .then(v => v - 3);  // 1
    
  2. 错误类型检测
    .catch(err => {
      if (err instanceof TypeError) { /* 特定错误处理 */ }
      else { /* 通用错误处理 */ }
    });
    
  3. 组合静态方法
    Promise.all([task1, task2])
      .then(results => console.log(results))
      .catch(err => console.error(err))
      .finally(() => console.log("全部完成"));
    

七、关联知识扩展

方法说明
Promise.all()等待所有 Promise 完成,任一失败即拒绝
Promise.race()竞争第一个完成的 Promise,快照决
Promise.any()等待任意一个 Promise 成功,全部失败才拒绝
async/await基于 Promise 的语法糖,提供同步风格的异步代码书写体验

总结.then().catch().finally() 构成了 Promise 链式调用的完整闭环,通过合理组织这三个环节,可以实现清晰的异步流程控制、健壮的错误处理以及可靠的收尾操作。

















🤔 参考 11

当然可以!下面是对 JavaScript 中 Promise().then().catch().finally() 的详细讲解,适合理解异步编程的完整流程。


一、Promise 基础回顾

Promise 是 JavaScript 中处理异步操作的标准方式。一个 Promise 对象代表一个最终会完成(成功或失败)的操作。

它有三种状态:

  • pending:初始状态,还未完成。
  • fulfilled:操作成功完成。
  • rejected:操作失败。

二、Promise 流程图概览

Promise 创建
     |
     v
  pending
     |
     v
fulfilled  rejected
     |
     v
.then()  .catch() 处理
     |
     v
.finally()(无论成功或失败都会执行)

三、详解每个部分

     1. Promise() :创建一个 Promise

new Promise((resolve, reject) => {
  // 异步操作
  if (成功) {
    resolve("成功结果");
  } else {
    reject("失败原因");
  }
});

     2. .then(onFulfilled, onRejected) :处理成功

  • 用于处理 Promise 成功(fulfilled)的状态。
  • 第一个参数是成功回调函数。
  • 第二个参数是失败回调函数(可选,推荐使用 .catch())。
.then((result) => {
  console.log("成功:", result);
})

     3. .catch(onRejected) :处理失败

  • 用于捕获 Promise 链中的错误。
  • 推荐统一使用 .catch() 来处理失败。
.catch((error) => {
  console.error("出错了:", error);
})

     4. .finally(onFinally) :无论成功或失败都会执行

  • .finally() 中的回调函数 不接收任何参数
  • 通常用于执行清理操作(如隐藏加载动画、关闭连接等)。
  • 无论 Promise 成功还是失败,都会执行。
.finally(() => {
  console.log("无论成功或失败,我都会执行");
});

四、完整示例

new Promise((resolve, reject) => {
  // 模拟异步操作
  setTimeout(() => {
    const success = Math.random() > 0.5;
    if (success) {
      resolve("数据加载成功");
    } else {
      reject("网络错误");
    }
  }, 1000);
})
  .then((result) => {
    console.log("成功:", result);
  })
  .catch((error) => {
    console.error("失败:", error);
  })
  .finally(() => {
    console.log("请求结束");
  });

五、链式调用与返回值

回调返回值新 Promise 的状态
返回普通值(如字符串、数字)fulfilled,值为返回值
返回新的 Promise由这个 Promise 决定
抛出异常(throw)rejected,值为异常信息

六、常见注意事项

  1. .finally() 不会影响 Promise 链的值
  2. .then().catch() 都可以链式调用
  3. 推荐使用 .catch() 统一处理错误
  4. .finally() 不接受参数,用于清理操作

七、总结

方法说明
Promise()创建一个异步操作,返回 Promise 对象
.then()处理成功的结果,支持链式调用
.catch()捕获失败或异常,推荐统一使用
.finally()无论成功或失败都会执行,用于清理操作

掌握 Promise().then().catch().finally() 是现代 JavaScript 异步编程的基础,能帮助你写出结构清晰、易于维护的异步代码。

















🤔 参考 12

Promise 链式调用详解: .then() 、 .catch() 、 .finally()

     核心概念图示

         创建
        ┌───────┐
        │ Promise │
        └───┬───┘
            │
.then() ────>│<──── .catch()
    │        │        │
    │  ┌─────▼─────┐  │
    │  │ Pending   │  │
    │  └─────┬─────┘  │
    │        │        │
resolve()    │    reject()
    │        │        │
    │  ┌─────▼─────┐  │
    └──│ Fulfilled ├──┘
       └─────┬─────┘
             │<──── .finally()
             ▼
       最终处理

     1. .then() 方法 作用:处理 Promise 成功状态(Fulfilled)
特性

  • 接收两个可选参数:onFulfilledonRejected 回调
  • 返回新的 Promise 对象,支持链式调用
  • 值穿透:当回调未定义时,直接传递前值
fetchData()
  .then(
    // 成功回调
    result => {
      console.log("成功:", result);
      return processData(result); // 返回新值/Promise
    },
    // 可选:失败回调(通常不在此处理)
    error => {
      console.warn("局部错误:", error);
      return recoveryData(); // 局部恢复
    }
  )
  .then(processedData => {
    console.log("二次处理:", processedData);
  });

     2. .catch() 方法 作用:专门处理 Promise 失败状态(Rejected)
本质.catch(onRejected) 等价于 .then(null, onRejected)

fetchData()
  .then(processData)
  .catch(error => {
    console.error("全局捕获:", error);
    
    // 可选择:
    // 1) 返回恢复值 → 后续 then 继续执行
    // return fallbackData;
    
    // 2) 抛出新错误 → 触发后续 catch
    throw new Error("处理失败", { cause: error });
  })
  .then(data => {
    // 当 catch 返回值时执行
    console.log("恢复后数据:", data);
  })
  .catch(err => {
    // 当 catch 抛出错误时执行
    console.error("二次错误:", err);
  });

     3. .finally() 方法 作用:无论成功/失败都会执行
特性

  • 不接收任何参数(无法获取结果/错误)
  • 不影响 Promise 链的值传递
  • 适合执行清理操作(如隐藏加载动画)
let isLoading = true;

fetchData()
  .then(data => {
    console.log("获取数据:", data);
    return data;
  })
  .catch(err => {
    console.error("请求失败:", err);
    return null;
  })
  .finally(() => {
    isLoading = false; // 无论成败都会执行
    console.log("清理完成");
  })
  .then(finalResult => {
    console.log("最终结果:", finalResult); 
    // 仍能获取 then/catch 返回的值
  });

执行流程详解

     基础流程示例

const example = new Promise((resolve, reject) => {
  Math.random() > 0.5 ? resolve("🍎") : reject("💥");
});

example
  .then(fruit => {
    console.log("收到:", fruit);
    return fruit + "汁";
  })
  .catch(err => {
    console.error("错误:", err);
    return "🍹备用饮料";
  })
  .finally(() => {
    console.log("=== 处理结束 ===");
  })
  .then(drink => {
    console.log("饮用:", drink);
  });

可能的输出

// 成功情况:
收到: 🍎
=== 处理结束 ===
饮用: 🍎汁

// 失败情况:
错误: 💥
=== 处理结束 ===
饮用: 🍹备用饮料

     状态处理规则表

前一个 Promise 状态调用的方法返回值类型新 Promise 状态
Fulfilled.then()普通值Fulfilled (新值)
Fulfilled.then()Promise 对象跟随该 Promise
Rejected.catch()普通值Fulfilled (恢复值)
Rejected.catch()抛出的错误Rejected (新错误)
Any.finally()无返回值保持原状态
Any.finally()抛出的错误Rejected (新错误)

关键特性对比

方法接收参数返回值影响是否改变状态典型用途
.then()结果值决定新 Promise 的值/状态数据处理
.catch()错误对象决定错误恢复或传递错误处理
.finally()不影响值传递仅自身出错时清理操作

高级用法示例

     1. 链式错误处理

startWorkflow()
  .then(step1)
  .then(step2)
  .catch(handleSpecificError) // 处理特定错误
  .then(step3)
  .catch(handleGeneralError); // 通用错误处理

     2. 资源清理保证

openFile()
  .then(file => {
    return processFile(file);
  })
  .finally(() => {
    closeFile(); // 永远执行文件关闭
  });

     3. 异步 finally 处理

fetchData()
  .finally(async () => {
    await logCleanup(); // 支持异步操作
    console.log("清理完成");
  });

常见误区与解决方案

  1. 忘记返回新值

    // 错误:值传递中断
    .then(data => { save(data); }) // 没有return
    .then(saved => console.log(saved)) // 输出 undefined
    
    // 正确
    .then(data => {
      save(data);
      return data; // 显式返回
    })
    
  2. finally 中返回值

    // 错误:试图改变结果
    .finally(() => "新值") // 无效!
    
    // 正确:finally 应只做清理
    .finally(cleanup)
    
  3. 未处理的拒绝

    // 危险:缺少 catch 处理
    riskyOperation().then(console.log);
    
    // 安全:添加终结处理
    riskyOperation()
      .then(console.log)
      .catch(console.error);
    

最佳实践

  1. 链式调用原则

    graph LR
    A[初始Promise] --> B[.then(数据处理)]
    B --> C[.then(进一步处理)]
    C --> D[.catch(错误处理)]
    D --> E[.finally(清理)]
    
  2. 错误处理策略

    • 使用 .catch() 作为错误处理的终点
    • 特定步骤错误在局部 .then 的第二个参数处理
    • 使用 throw new Error() 传递错误上下文
  3. 资源管理

    // 安全资源访问模式
    getResource()
      .then(useResource)
      .then(processResult)
      .catch(handleError)
      .finally(releaseResource); // 确保资源释放
    

浏览器支持

  • 所有现代浏览器(Chrome 32+、Firefox 29+、Safari 8+、Edge 12+)
  • Node.js 0.12+(需启用 Promise flag)
  • 完整支持:ES2015(ES6) 及以上环境

掌握 .then().catch().finally() 的链式调用,是构建健壮异步代码的基础,它们共同构成了 Promise 错误处理和数据流转的核心机制。

















🤔 参考 13

Promise 链式调用详解: .then() , .catch() , .finally()

     核心概念图示

[Promise]
   │
   ├──成功──▶ .then(onFulfilled) ──▶ [新Promise]
   │
   ├──失败──▶ .catch(onRejected)  ──▶ [新Promise]
   │
   └──终局──▶ .finally(onFinally) ──▶ [继承原状态的新Promise]

     1. .then() 方法 作用:处理 Promise 的完成(fulfilled)或拒绝(rejected)状态
语法

promise.then(
  onFulfilled?,  // 成功回调(可选)
  onRejected?    // 失败回调(可选)
)

特性

  • 返回新 Promise 对象
  • 回调函数返回值决定新 Promise 状态:
    .then(value => {
      return 42;           // 新 Promise 以 42 兑现
      return Promise.resolve(); // 继承返回的 Promise 状态
      throw new Error();   // 新 Promise 拒绝
    })
    
  • 可省略任意回调:
    // 只处理成功
    promise.then(result => {...})
    
    // 只处理失败(不推荐,用.catch()更好)
    promise.then(null, error => {...})
    

     2. .catch() 方法 作用:专门处理拒绝状态(rejected)
语法

promise.catch(onRejected)

等效于

promise.then(null, onRejected)

关键特性

  • 捕获链中所有上游错误
  • 返回新 Promise 对象
  • 可恢复错误状态:
    fetchData()
      .catch(error => {
        console.error(error);
        return "默认值"; // 新 Promise 以此值兑现
      })
      .then(data => ...) // 接收到"默认值"
    

     3. .finally() 方法 作用:无论成功/失败都执行的清理逻辑
语法

promise.finally(onFinally)

核心特性

  1. 不改变原 Promise 结果
    Promise.resolve(2)
      .finally(() => 100) // 忽略返回值
      .then(v => console.log(v)) // 输出 2
    
  2. 传递原状态
    Promise.reject("error")
      .finally(() => {})
      .catch(e => console.log(e)) // 输出 "error"
    
  3. 适合执行清理操作
    let loading = true;
    
    fetchData()
      .then(data => ...)
      .catch(err => ...)
      .finally(() => {
        loading = false; // 无论成败都关闭加载状态
      });
    

完整执行流程示例

function simulateAsync(succeed) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      succeed ? resolve("成功数据") : reject("错误原因");
    }, 500);
  });
}

// 完整链式调用
simulateAsync(true)
  .then(data => {
    console.log("第一步成功:", data); // 输出: 第一步成功: 成功数据
    return "处理后的数据";
  })
  .catch(err => {
    console.error("捕获错误:", err);
    return "备用数据";
  })
  .then(result => {
    console.log("第二步接收:", result); // 输出: 第二步接收: 处理后的数据
    throw new Error("手动错误");
  })
  .finally(() => {
    console.log("清理资源"); // 总会执行
  })
  .catch(err => {
    console.error("最终错误:", err.message); // 输出: 最终错误: 手动错误
  });

状态转换规则详解

操作输入状态回调执行输出状态
.then(fn)fulfilledfn(value)由回调返回值决定
.then(null, fn)rejectedfn(reason)由回调返回值决定
.catch(fn)rejectedfn(reason)由回调返回值决定
.finally(fn)anyfn()继承输入状态

最佳实践指南

  1. 链式顺序:按逻辑顺序组织调用

    // ✅ 清晰流程
    fetchData()
      .then(process)
      .then(save)
      .catch(handleError)
      .finally(cleanup);
    
    // ❌ 混乱结构
    fetchData().then(process).catch(handleError).then(save).finally(cleanup);
    
  2. 错误处理

    // 危险:可能遗漏错误
    promise.then(handler); 
    
    // 安全:始终捕获错误
    promise
      .then(handler)
      .catch(errorLogger);
    
  3. 资源清理

    let resource = acquireResource();
    
    processAsync()
      .then(useResource)
      .finally(() => {
        releaseResource(resource); // 确保资源释放
      });
    
  4. 返回值注意

    // finally中不要返回有效值
    .finally(() => {
      cleanup();
      // 不要返回任何值! 
    })
    

常见陷阱及解决方案

  1. 未捕获的拒绝

    // ❌ 错误会崩溃
    new Promise((_, reject) => reject("未处理"));
    
    // ✅ 添加catch处理
    new Promise((_, reject) => reject("已处理"))
      .catch(e => console.log(e));
    
  2. finally中的错误

    Promise.resolve()
      .finally(() => {
        throw new Error("finally中的错误"); 
      })
      .catch(e => console.log(e)); // 必须捕获!
    
  3. 回调地狱转换

    // 传统回调地狱
    asyncFunc1(() => {
      asyncFunc2(() => {
        asyncFunc3(() => {...})
      })
    })
    
    // ✅ Promise解决方案
    asyncFunc1()
      .then(() => asyncFunc2())
      .then(() => asyncFunc3())
      .catch(handleAllErrors);
    

浏览器兼容性

  • 所有现代浏览器(Chrome 32+, Firefox 29+, Edge 12+, Safari 8+)
  • Node.js 0.12+(需启用--harmony标志)
  • 旧环境使用 core-jses6-promise polyfill

总结表格

方法最佳场景返回值影响错误处理能力
.then()处理成功/转换数据决定新Promise可处理当前错误
.catch()集中错误处理/恢复操作决定新Promise处理链中所有错误
.finally()清理资源/执行终局操作不影响结果需单独错误处理
flowchart TD
    A[Promise] -->|fulfilled| B[.then onFulfilled]
    A -->|rejected| C[.catch onRejected]
    B --> D[新Promise]
    C --> D
    D -->|any| E[.finally]
    E --> F[继承状态的新Promise]

黄金法则

  1. 每个 .then() 应专注于单一职责
  2. 使用 .catch() 作为错误处理的最后防线
  3. .finally() 仅用于不影响结果的清理操作
  4. 始终返回 Promise 链以保持可扩展性

















🤔 参考 14 then的第二个回调 与 catch的回调

在 JavaScript 的 Promise 链中,.then() 的第二个回调和 .catch() 的回调都用于错误处理,但它们的触发条件和链式行为有重要区别。以下是详细对比和示例:


一、核心区别

特性.then(onFulfilled, onRejected).catch(onRejected)
作用范围仅捕获前一个 Promise 的拒绝捕获链中所有未被处理的拒绝
错误冒泡不捕获当前 .then() 内部的错误捕获链中任意位置的错误
代码可读性成功/失败逻辑混合错误处理集中
推荐场景处理特定步骤的拒绝全局错误处理

二、执行流程对比      场景 1:直接拒绝的 Promise

// 示例 1
new Promise((_, reject) => reject("Error"))
  .then(
    (v) => console.log("Success:", v), // 跳过
    (e) => console.log("Then Error:", e) // 触发
  )
  .catch((e) => console.log("Catch Error:", e)); // 跳过

// 输出:Then Error: Error

     场景 2:链式调用中的错误

// 示例 2
new Promise((resolve) => resolve("Data"))
  .then(
    (v) => { throw new Error("Oops!"); }, // 抛出错误
    (e) => console.log("Then Error:", e) // 跳过(无法捕获当前步骤的错误)
  )
  .catch((e) => console.log("Catch Error:", e)); // 触发

// 输出:Catch Error: Error: Oops!

     场景 3:混合使用

// 示例 3
new Promise((resolve) => resolve("Data"))
  .then(
    (v) => { throw new Error("Oops!"); },
    (e) => console.log("Then Error:", e) // 跳过
  )
  .then(
    (v) => console.log("Next Success:", v), // 跳过
    (e) => console.log("Next Then Error:", e) // 触发(捕获前一个 .then 的错误)
  )
  .catch((e) => console.log("Catch Error:", e)); // 跳过

// 输出:Next Then Error: Error: Oops!

三、关键规则

  1. .then() 的第二个回调

    • 只能捕获前一个 Promise 的拒绝
    • 无法捕获当前 .then() 成功回调中抛出的错误(如示例 2)。
    • 若未处理错误,错误会继续传递到后续的 .catch().then() 的第二个回调。
  2. .catch() 的回调

    • 捕获链中所有未被处理的拒绝(包括前面 .then() 内部的错误)。
    • 相当于 .then(null, onRejected),但更推荐用于集中错误处理。

四、使用建议

  1. 优先使用 .catch()

    • 放在 Promise 链的末尾,捕获所有未处理的错误。
    fetchData()
      .then(processData)
      .then(displayData)
      .catch(handleError); // 集中处理所有错误
    
  2. 特定步骤的拒绝处理

    • 使用 .then() 的第二个回调处理特定 Promise 的拒绝。
    fetchData()
      .then(
        (data) => processData(data),
        (error) => { // 处理 fetchData 的拒绝
          console.log("Fetch failed:", error);
          return fallbackData; // 恢复链式调用
        }
      )
      .then(displayData);
    
  3. 避免混合使用

    • 不要在同一个链中同时用 .then(onRejected).catch() 处理同一错误,可能导致重复处理。

五、总结

  • .then(null, onRejected):精准处理特定步骤的拒绝,但无法捕获当前步骤的错误。
  • .catch():全局兜底,确保所有错误被处理,代码更健壮。

根据具体需求选择合适的方式,通常结合使用两者可以实现清晰的错误处理逻辑。

















🤔 参考 15 Promise 错误处理:then 的第二个回调 vs catch 回调的深度解析

在 JavaScript 的 Promise 链中,错误处理有两种主要方式:使用 then() 的第二个回调函数和使用 catch() 方法。虽然它们都可以处理 rejected 状态的 Promise,但它们在行为和使用场景上有重要区别。

核心区别概览

特性then 的第二个回调catch 回调
捕获范围仅捕获前一个 Promise 的 rejection捕获链中前面所有 Promise 的 rejection 或错误
链式影响错误处理后返回 resolved Promise错误处理后返回 resolved Promise
位置灵活性必须紧跟在可能失败的 Promise 后可放置在链的任意位置
错误类型处理可针对特定操作进行错误处理通常作为全局错误处理器
嵌套错误无法捕获自身回调中的错误可捕获前面所有回调中的错误

详细对比分析

     1. 基本语法

// then 的第二个回调
promise
  .then(
    successHandler, 
    errorHandler // 仅处理前一个 promise 的 rejection
  );

// catch 回调
promise
  .then(successHandler)
  .catch(errorHandler); // 处理链中所有错误

     2. 错误捕获范围

关键区别then 的第二个回调只处理直接前驱 Promise 的 rejection,而 catch 会捕获链中前面所有 Promise 的 rejection 和错误。

// 示例 1: then 的第二个回调
Promise.resolve()
  .then(() => {
    throw new Error('Step 1 error');
  })
  .then(
    () => console.log('不会执行'),
    (err) => console.log('捕获错误:', err.message) // Step 1 error
  )
  .then(() => {
    console.log('继续执行');
    throw new Error('Step 3 error');
  })
  .then(
    null, 
    (err) => console.log('捕获新错误:', err.message) // Step 3 error
  );

// 示例 2: catch 回调
Promise.resolve()
  .then(() => {
    throw new Error('Step 1 error');
  })
  .catch(err => { // 捕获 Step 1 error
    console.log('全局捕获:', err.message);
    throw new Error('处理中的新错误');
  })
  .then(() => console.log('不会执行'))
  .catch(err => console.log('捕获后续错误:', err.message)); // 处理中的新错误

     3. 链式行为差异

catch 更像是错误处理的 "安全网",而 then 的第二个回调是 "精确拦截器"。

// 错误恢复后的链式行为
Promise.reject(new Error('Initial error'))
  .then(
    result => console.log('成功', result),
    err => {
      console.log('处理错误:', err.message); // Initial error
      return '恢复值';
    }
  )
  .then(result => console.log('继续执行:', result)); // 继续执行: 恢复值

Promise.reject(new Error('Initial error'))
  .catch(err => {
    console.log('捕获错误:', err.message); // Initial error
    return '恢复值';
  })
  .then(result => console.log('继续执行:', result)); // 继续执行: 恢复值

     4. 嵌套错误处理

// then 的第二个回调无法捕获自身错误
Promise.resolve()
  .then(
    () => '成功',
    (err) => { 
      throw new Error('处理错误时的新错误'); // 未被捕获!
    }
  )
  .catch(err => console.log('被 catch 捕获:', err.message)); 

// catch 可以处理前面的错误
Promise.reject(new Error('原始错误'))
  .catch(err => {
    console.log('捕获:', err.message); // 原始错误
    throw new Error('处理中产生的新错误');
  })
  .catch(err => console.log('捕获新错误:', err.message)); // 处理中产生的新错误

使用场景推荐

     使用 then 的第二个回调当:

  1. 需要处理特定步骤的错误并立即恢复
  2. 不同步骤需要不同的错误处理逻辑
  3. 需要区分成功和失败路径
fetchUserData(userId)
  .then(
    user => updateUserProfile(user), // 成功处理
    err => { // 仅处理 fetchUserData 的错误
      console.error('获取用户失败:', err);
      return getCachedUser(userId); // 回退到缓存
    }
  )
  .then(profile => saveProfile(profile))
  .catch(err => console.error('全局错误:', err)); // 处理其他错误

     使用 catch 当:

  1. 需要全局错误处理器
  2. 处理链中任何位置的错误
  3. 简化错误处理逻辑
  4. 保证捕获所有可能的错误
startWorkflow()
  .then(step1)
  .then(step2)
  .then(step3)
  .catch(err => {
    console.error('工作流失败:', err);
    notifyAdmin(err);
    rollbackChanges();
  });

高级模式与最佳实践

     1. 组合使用模式

fetchData()
  .then(processData, handleFetchError) // 特定错误处理
  .then(saveData)
  .catch(handleUnexpectedError); // 全局兜底

     2. 错误类型区分

class NetworkError extends Error {}
class ValidationError extends Error {}

apiRequest()
  .then(
    response => validateResponse(response),
    err => { // 仅处理网络错误
      if (err instanceof NetworkError) {
        return retryRequest();
      }
      throw err; // 重新抛出其他错误
    }
  )
  .catch(err => { // 处理其他所有错误
    if (err instanceof ValidationError) {
      showUserError('无效数据');
    } else {
      showGenericError();
    }
  });

     3. 错误恢复与转换

getPrimaryData()
  .catch(err => { // 主数据源失败
    console.warn('主数据源失败, 使用备用源:', err);
    return getFallbackData();
  })
  .then(data => {
    // 无论主备都统一处理
  });

     4. 最终处理 (finally)

let isLoading = true;

fetchResource()
  .then(data => process(data))
  .catch(err => logError(err))
  .finally(() => {
    isLoading = false; // 无论成功失败都执行
    cleanupResources();
  });

实际应用示例

     1. API 请求与错误处理

async function fetchUserWithFallback(userId) {
  return fetch(`/api/users/${userId}`)
    .then(response => {
      if (!response.ok) {
        throw new NetworkError(`HTTP ${response.status}`);
      }
      return response.json();
    })
    .then(
      user => transformUserData(user),
      err => { // 仅处理网络/HTTP错误
        console.warn('API请求失败, 使用缓存:', err);
        return getCachedUser(userId);
      }
    )
    .catch(err => { // 兜底处理
      console.error('完全失败:', err);
      return getDefaultUser();
    });
}

     2. 多步骤工作流

startPaymentProcess()
  .then(validateCart)
  .then(
    cart => chargePayment(cart.total),
    err => { // 仅处理购物车验证错误
      if (err instanceof CartValidationError) {
        return fixCartIssues().then(validateCart);
      }
      throw err;
    }
  )
  .then(paymentResult => createOrder(paymentResult))
  .then(order => sendConfirmation(order))
  .catch(err => { // 处理所有其他错误
    console.error('支付流程失败:', err);
    cancelTransaction();
    alertUser('支付失败, 请重试');
  });

     3. 错误监控与报告

function trackError(error, context) {
  // 发送错误到监控系统
  console.error(`[${context}]`, error);
}

fetchAnalyticsData()
  .then(processData)
  .then(
    result => saveToDatabase(result),
    err => { // 仅处理数据处理错误
      trackError(err, 'data-processing');
      throw err; // 继续传播
    }
  )
  .catch(err => { // 捕获所有错误
    trackError(err, 'global-catch');
    showErrorMessage();
  });

常见错误与解决方案

     问题1:错误被吞没

// 错误: 忘记返回或抛出错误
Promise.reject(new Error('test'))
  .catch(err => {
    console.log('捕获错误'); // 但错误被处理,链继续
  })
  .then(() => console.log('继续执行')); // 会执行

// 解决方案: 需要时重新抛出
Promise.reject(new Error('test'))
  .catch(err => {
    console.log('捕获错误');
    throw err; // 重新抛出
  })
  .catch(err => console.log('再次捕获')); // 会被捕获

     问题2:过度嵌套

// 反模式: 嵌套的 then 错误处理
getData()
  .then(result => {
    process(result)
      .then(() => console.log('成功'))
      .catch(err => console.log('处理错误')); // 内部处理
  })
  .catch(err => console.log('外部捕获')); // 不会捕获内部错误

// 解决方案: 扁平化处理
getData()
  .then(process) // 直接传递函数
  .then(() => console.log('成功'))
  .catch(err => console.log('统一处理')); // 处理所有错误

     问题3:忽略异步错误

// 错误: 忘记返回 Promise
function updateUser(user) {
  saveToDB(user) // 忘记 return
    .catch(err => logError(err));
}

updateUser(user)
  .then(() => console.log('完成')) // 立即执行,不等待
  .catch(err => console.log('不会捕获')); // 不会执行

// 解决方案: 始终返回 Promise
function updateUser(user) {
  return saveToDB(user) // 正确返回
    .catch(err => {
      logError(err);
      throw err; // 重新抛出以保持拒绝状态
    });
}

最佳实践总结

  1. 优先使用 catch:在链的末尾添加全局错误处理器

    apiCall()
      .then(process)
      .then(save)
      .catch(handleGlobalError); // 推荐
    
  2. 特定错误使用 then 的第二个参数

    fetchData()
      .then(parseJSON, handleNetworkError) // 特定错误处理
      .then(processData)
      .catch(handleOtherErrors); // 全局处理
    
  3. 始终返回或抛出:在错误处理程序中

    .catch(err => {
      logError(err);
      throw err; // 保持拒绝状态
      // 或 return recoveryValue; // 恢复为成功状态
    })
    
  4. 使用自定义错误类型

    class ApiError extends Error {
      constructor(message, status) {
        super(message);
        this.status = status;
      }
    }
    
  5. 结合 finally 进行清理

    loadResource()
      .then(useResource)
      .catch(handleError)
      .finally(cleanup); // 总是执行
    
  6. 避免嵌套:保持 Promise 链扁平化

    // 避免
    getData().then(a => {
      getMoreData(a).then(b => {
        // ...
      });
    });
    
    // 推荐
    getData()
      .then(a => getMoreData(a))
      .then(b => { /* ... */ });
    

结论

  1. then 的第二个回调

    • 精确处理特定 Promise 的 rejection
    • 适合局部错误恢复
    • 无法捕获链中后续错误
  2. catch 方法

    • 捕获链中所有前面的错误
    • 适合作为全局错误处理器
    • 可以处理自身之前的任何错误

在大多数场景中,推荐在 Promise 链的末尾使用 catch 作为全局错误处理器,同时使用 then 的第二个参数来处理需要特定恢复策略的局部错误。这种组合方式既能提供精确的错误处理,又能确保没有错误被意外忽略。

理解两者的区别和适用场景,将帮助你编写更健壮、可维护的异步 JavaScript 代码。