javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > js promise

JavaScript Promise错误处理与最佳实践

作者:风茫

Promise是ES6异步编程解决方案,解决回调地狱问题,支持链式调用、统一错误处理,是现代JavaScript异步处理的基石,本文给大家介绍JavaScript Promise错误处理与最佳实践,感兴趣的朋友一起看看吧

一句话概括
Promise 是 ES6 引入的异步编程解决方案,用于表示一个异步操作的最终完成或失败,以及其返回的值。它解决了“回调地狱”(Callback Hell)问题,使异步代码更清晰、可读、可维护。

一、为什么需要Promise?(历史背景)

Promise 出现之前,JavaScript 主要通过 回调函数(Callback) 处理异步操作:

// 回调地狱(Callback Hell)
doTask1((err, result1) => {
  if (err) return handleError(err);
  doTask2(result1, (err, result2) => {
    if (err) return handleError(err);
    doTask3(result2, (err, result3) => {
      if (err) return handleError(err);
      console.log('完成:', result3);
    });
  });
});

回调函数的痛点:

Promise 的出现就是为了解决这些问题。

二、Promise的三种状态(States)

Promise 对象有且仅有三种状态,一旦改变不可逆

状态说明
pending初始状态,进行中
fulfilled成功状态,操作成功完成
rejected失败状态,操作失败
const promise = new Promise((resolve, reject) => {
  // 初始状态:pending
  if (success) {
    resolve(value);  // → fulfilled
  } else {
    reject(error);   // → rejected
  }
});

三、Promise构造函数

new Promise(executor)
const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    Math.random() > 0.5 ? resolve('成功') : reject('失败');
  }, 1000);
});

resolve不同值的区别

  1. 普通值或者对象,那么这个值会作为then回调的参数
  2. 另外一个Promise对象,那么这个新Promise会决定原来Promise的状态
  3. thenable对象:这对象中有实现then方法,那么就会执行该then方法,并且根据then方法的结果来决定Promise的状态
const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(1);
  }, 3000);
});
const promise = new Promise((resolve, reject) => {
  // 1. 普通值
  // resolve(1);
  // resolve([
  //   {
  //     name: "风茫",
  //     age: 18,
  //   },
  //   {
  //     name: "fengmang",
  //     age: 30,
  //   },
  // ]);
  // 2. resolve(promise)
  // 如果resolve的值为Promise对象,那么当前的Promise的状态由传入的promise来决定
  // resolve(p);
  // 3. resolve(thenable对象)
  // thenable对象: 对象有then方法,那么就会执行then方法,并且根据then方法的结果来决定Promise的状态
  resolve({
    name: "风茫",
    then: function (resolve, reject) {
      Math.random() > 0.5 ? resolve(100) : reject("失败");
    },
  });
});
promise
  .then((res) => {
    console.log("res :>> ", res);
  })
  .catch((err) => {
    console.log(err);
  });

四、Promise的核心方法

1..then(onFulfilled, onRejected)

注册成功和失败的回调。

p.then(
  (value) => { console.log(value); },      // fulfilled
  (error) => { console.error(error); }     // rejected
);

链式调用的关键:.then() 返回一个新的 Promise

then方法返回值

const promise = new Promise((resolve, reject) => {
  resolve("aaa");
});
const p2 = promise
  .then((res) => {
    console.log(res);
    return "bbb";
  })
  .then((res) => {
    console.log(res);
    return "ccc";
  });
p2.then((res) => {
  console.log(res);
}).catch((err) => {
  console.log(err);
});
/**
 * 输出结果:
 * aaa
 * bbb
 * ccc 
 */

解释

  1. Promise的 then方法是返回一个新的Promise,这个新Promise的决议是等到then方法传入的回调函数 有返回值 时进行决议
  2. 若是上一个then方法没有使用return返回,则下一个then方法接收到的值是undefined
  3. 若是在then方法中return一个新的Promise,则下一个then方法需要等到新Promise决议之后才会执行,将新的Promise决议结果返回给下一个then方法并执行then方法

2..catch(onRejected)

捕获错误,相当于 .then(null, onRejected)

p.catch(err => {
  console.error('出错了:', err);
});

推荐写法:链式 .then().catch(),统一错误处理

fetch('/api/data')
  .then(res => res.json())
  .then(data => console.log(data))
  .catch(err => console.error('请求失败:', err));

3..finally(onFinally)

无论成功或失败都会执行,常用于清理资源。

p.finally(() => {
  console.log('请求完成,关闭 loading...');
});

不接收参数,不改变结果,常用于加载状态、资源释放。

五、Promise静态方法

1.Promise.resolve(value)

作用:返回一个 fulfilled 的 Promise。

Promise.resolve(42).then(x => console.log(x)); // 42

等价于:

new Promise(resolve => resolve(42));

使用场景

let promise = Promise.resolve(42);
promise.then(function(value) {
 console.log(value); // 输出: 42
});
function maybeAsync() {
  if (/* some condition */) {
    return new Promise(/* ... */);
  } else {
    return 'immediate value';
  }
}
Promise.resolve(maybeAsync()).then(function(result) {
  console.log(result);
});
Promise.resolve().then(() => {
  console.log('This runs after the current call stack is cleared.');
});
 Promise.resolve()
     .then(() => console.log('First step'))
     .then(() => console.log('Second step'));

2.Promise.reject(reason)

返回一个 rejected 的 Promise。

Promise.reject('出错了').catch(err => console.log(err));

3.Promise.all(iterable)

作用:接收一个可迭代对象(通常是数组),其中每个元素都是一个 Promise,并发执行多个 Promise,返回一个新的Promise。全部成功才成功任一失败则整体失败

const p1 = Promise.resolve('A');
const p2 = Promise.resolve('B');
const p3 = Promise.reject('C');
Promise.all([p1, p2]).then(results => {
  console.log(results); // ['A', 'B']
});
Promise.all([p1, p2, p3]).catch(err => {
  console.log(err); // 'C'
});

适用于“所有请求都必须成功”的场景(如批量上传)。

4.Promise.race(iterable)

返回第一个完成的 Promise(无论是成功还是失败)。

const slow = new Promise(r => setTimeout(() => r('慢'), 2000));
const fast = new Promise(r => setTimeout(() => r('快'), 500));
Promise.race([slow, fast]).then(result => {
  console.log(result); // '快'
});

适用于“超时控制”:

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

5.Promise.allSettled(iterable)

等待所有 Promise 结束,无论成功或失败,返回结果数组。

Promise.allSettled([p1, p2, p3]).then(results => {
  results.forEach((result, i) => {
    if (result.status === 'fulfilled') {
      console.log(`p${i+1} 成功:`, result.value);
    } else {
      console.log(`p${i+1} 失败:`, result.reason);
    }
  });
});

适用于“不关心成败,只想知道所有结果”的场景。

6.Promise.any(iterable)

返回第一个成功的 Promise;如果全部失败,则抛出 AggregateError

const fail1 = Promise.reject('错误1');
const fail2 = Promise.reject('错误2');
const success = Promise.resolve('成功');
Promise.any([fail1, fail2, success]).then(res => {
  console.log(res); // '成功'
});

适用于“只要有一个成功即可”的场景(如多源请求)。

六、Promise的执行机制(微任务)

Promise 的回调(.then.catch)属于 微任务(microtask),在当前宏任务结束后立即执行。

console.log(1);
Promise.resolve().then(() => {
  console.log(2);
});
console.log(3);
// 输出:1 → 3 → 2

微任务优先级高于 setTimeout(宏任务)

setTimeout(() => console.log(1), 0);
Promise.resolve().then(() => console.log(2));
console.log(3);
// 输出:3 → 2 → 1

七、错误处理最佳实践

正确方式:使用.catch()

fetch('/api')
  .then(res => res.json())
  .then(data => { throw new Error('处理失败'); })
  .catch(err => console.error(err)); // 能捕获

错误方式:在.then中不处理错误

fetch('/api')
  .then(res => res.json(), err => console.error(err)) // 只能捕获 fetch 失败
  .then(data => { throw new Error('处理失败'); })     // 这个错误没被捕获!

建议:链式调用末尾加 .catch()

八、Promise的常见模式

1. 串行执行(链式调用)

function asyncTask(name) {
  return Promise.resolve().then(() => {
    console.log(`执行 ${name}`);
    return name;
  });
}
asyncTask('A')
  .then(() => asyncTask('B'))
  .then(() => asyncTask('C'));

2. 并行执行

Promise.all([
  asyncTask('A'),
  asyncTask('B'),
  asyncTask('C')
]).then(results => console.log('全部完成'));

3. 重试机制

function retry(fn, times = 3) {
  return fn().catch(err => {
    if (times <= 1) throw err;
    return retry(fn, times - 1);
  });
}
retry(() => fetch('/api')).catch(console.error);

九、Promise的局限性

问题说明
无法取消一旦创建,无法中途取消
错误冒泡未捕获的错误可能静默失败(Node.js 会警告)
无法获取进度只有成功/失败,不支持 onProgress
冗长的 .then复杂逻辑仍难读

解决方案:使用 async/await(ES2017)

async function getData() {
  try {
    const res = await fetch('/api');
    const data = await res.json();
    return data;
  } catch (err) {
    console.error('请求失败:', err);
  }
}

十、总结

项目说明
定位异步编程的标准化解决方案
核心价值解决回调地狱,提供链式调用和统一错误处理
关键方法.then().catch().finally()
静态方法allraceallSettledanyresolvereject
执行机制回调属于微任务,优先级高
现代替代async/await(基于 Promise

最终结论
Promise 是现代 JavaScript 异步编程的基石。即使你使用 async/await,其底层仍是 Promise。掌握 Promise 是成为合格前端/Node.js 开发者的必经之路

到此这篇关于JavaScript Promise错误处理与最佳实践的文章就介绍到这了,更多相关js promise内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文