ES6 Promise 详解:状态机制、核心方法与异步处理

作者:纸飞机

时间:2026-10-22

浏览:588

本文深入解析 ES6 Promise 的核心概念,涵盖其三种状态(pending、fulfilled、rejected)的转换规则及不可逆特性。详细讲解 then、catch、all、race、resolve 和 reject 等常用方法的使用场景与返回值逻辑,帮助开发者有效解决 Node.js 回调地狱问题,实现清晰可控的异步操作流程。

文章目录

Promise 的引入背景

Node.js 的出现极大地推动了 JavaScript 在服务端领域的发展,降低了前端开发者涉足后端开发的门槛。

然而,这并不意味着开发者自动成为了全栈工程师。全栈技能要求高度集中,远不止前端掌握 HTML 和交互逻辑、后端熟悉数据库增删改查那么简单。

接触过 Node.js 的开发者都知道,其核心特征是异步回调。虽然异步机制提升了程序执行效率,但也牺牲了代码可读性。当存在多个相互依赖的异步操作时,后一步需要前一步的结果,按照 Node.js 的传统执行逻辑,往往需要通过层层嵌套来实现有序执行。

针对这一痛点,ES6 标准引入了 Promise 机制。

Promise 的基本含义与状态

含义

Promise 对象用于表示一个异步操作的最终完成(或失败)及其结果值。简而言之,它专门用于处理异步操作:成功时执行相应的处理逻辑,失败时则捕获错误或终止后续操作。

其基本表示形式如下:


new Promise(
  /* executor */
  function(resolve, reject) {
    if (/* success */) {
      // ...执行代码
      resolve();
    } else { /* fail */
      // ...执行代码
      reject();
    }
  }
);

其中,Promise 构造函数接收一个执行器函数(executor)作为参数,该函数包含 resolve 和 reject 两个参数。执行器内部通常包含异步逻辑:若操作成功,调用 resolve() 将实例状态设为 fulfilled(已完成);若操作失败,则调用 reject() 将状态设为 rejected(已失败)。

可以将 Promise 对象类比为工厂流水线。从职能角度看,它仅有三种状态:初始状态(刚启动)、加工成功和加工失败(出现故障)。同理,Promise 对象也有三种状态:

  1. pending:初始状态,也称为未定状态,即初始化 Promise 并调用执行器函数后的初始状态。
  2. fulfilled:完成状态,表示异步操作成功。
  3. rejected:失败状态,表示异步操作失败。

Promise 仅有两种状态转换路径:

  1. 操作成功:从 pending 转换为 fulfilled。
  2. 操作失败:从 pending 转换为 rejected。

这种状态转换是单向且不可逆的,一旦状态确定为 fulfilled 或 rejected,就无法再回到初始的 pending 状态。

Promise 核心方法详解

方法

Promise.prototype.then()

Promise 对象包含 then 方法,调用 then() 后会返回一个新的 Promise 对象,这意味着实例化的 Promise 支持链式调用。此外,then() 方法可接收两个函数参数:一个用于处理成功结果,另一个用于处理错误结果。

示例如下:


var promise1 = new Promise(function(resolve, reject) {
 // 2秒后置为接收状态
 setTimeout(function() {
  resolve('success');
 }, 2000);
});

promise1.then(function(data) {
 console.log(data); // success
}, function(err) {
 console.log(err); // 不执行
}).then(function(data) {
 // 上一步的then()方法没有返回值
 console.log('链式调用:' + data); // 链式调用:undefined 
}).then(function(data) {
 // ....
});

此处主要关注 promise1.then() 调用后返回的新 Promise 对象的状态,它是 pending、fulfilled 还是 rejected?

返回的新 Promise 对象状态主要取决于 promise1.then() 方法内部的返回值,大致分为以下几种情况:

  1. 如果 then() 方法中返回了一个具体的参数值,那么返回的新 Promise 将变为接收状态(fulfilled)。
  2. 如果 then() 方法中抛出了一个异常,那么返回的新 Promise 将变为拒绝状态(rejected)。
  3. 如果 then() 方法中调用了 resolve(),那么返回的新 Promise 将变为接收状态(fulfilled)。
  4. 如果 then() 方法中调用了 reject(),那么返回的新 Promise 将变为拒绝状态(rejected)。
  5. 如果 then() 方法返回了一个处于未知状态(pending)的新 Promise 实例,那么返回的新 Promise 将保持未知状态。
  6. 如果 then() 方法没有明确指定 resolve(data)、reject(data) 或 return data,那么返回的新 Promise 默认为接收状态(fulfilled),并可继续向下传递。

状态转换实例如下:


var promise2 = new Promise(function(resolve, reject) {
 // 2秒后置为接收状态
 setTimeout(function() {
  resolve('success');
 }, 2000);
});

promise2
 .then(function(data) {
  // 上一个then()调用了resolve,置为fulfilled态
  console.log('第一个then');
  console.log(data);
  return '2';
 })
 .then(function(data) {
  // 此时这里的状态也是fulfilled, 因为上一步返回了2
  console.log('第二个then');
  console.log(data); // 2

  return new Promise(function(resolve, reject) {
   reject('把状态置为rejected error'); // 返回一个rejected的Promise实例
  });
 }, function(err) {
  // error
 })
 .then(function(data) {
  /* 这里不运行 */
  console.log('第三个then');
  console.log(data);
  // ....
 }, function(err) {
  // error回调
  // 此时这里的状态也是fulfilled, 因为上一步使用了reject()来返回值
  console.log('出错:' + err); // 出错:把状态置为rejected error
 })
 .then(function(data) {
  // 没有明确指定返回值,默认返回fulfilled
  console.log('这里是fulfilled态');
});

Promise.prototype.catch()

catch() 方法与 then() 类似,均返回一个新的 Promise 对象,主要用于捕获异步操作中出现的异常。因此,通常省略 then() 方法的第二个参数,将错误处理控制权交给后续的 catch() 函数,示例如下:


var promise3 = new Promise(function(resolve, reject) {
 setTimeout(function() {
  reject('reject');
 }, 2000);
});

promise3.then(function(data) {
 console.log('这里是fulfilled状态'); // 这里不会触发
 // ...
}).catch(function(err) {
 // 最后的catch()方法可以捕获在这一条Promise链上的异常
 console.log('出错:' + err); // 出错:reject
});

Promise.all()

Promise.all() 接收一个参数,该参数必须是可迭代的,例如数组。

它通常用于处理并发异步操作,即这些操作结果互不干扰但需异步执行。其最终状态仅有两种:成功或失败。

其状态受参数内各个值的状态影响:只有当内部所有状态均为 fulfilled 时,Promise.all() 才会变为 fulfilled;否则,只要有一个状态为 rejected,它便会变为 rejected。

成功调用后返回一个数组,数组中的值按传入参数的顺序排列,即按照传入数组的操作结果顺序返回。示例如下:


// 置为fulfilled状态的情况
var arr = [1, 2, 3];
var promises = arr.map(function(e) {
 return new Promise(function(resolve, reject) {
  resolve(e * 5);
 });
});

Promise.all(promises).then(function(data) {
  // 有序输出
 console.log(data); // [5, 10, 15]
 console.log(arr); // [1, 2, 3]
});

// 置为rejected状态的情况
var arr = [1, 2, 3];
var promises2 = arr.map(function(e) {
 return new Promise(function(resolve, reject) {
  if (e === 3) {
   reject('rejected');
  }
  resolve(e * 5);
 });
});

Promise.all(promises2).then(function(data) {
 // 这里不会执行
 console.log(data);
 console.log(arr);
}).catch(function(err) {
 console.log(err); // rejected
});

Promise.race()

Promise.race() 与 Promise.all() 类似,都接收一个可迭代的参数。不同之处在于,Promise.race() 的状态变化不受所有参数状态的影响,只要参数中有一个值的状态发生改变,该 Promise 的状态即随之改变。正如 race 一词的字面意思,谁跑得快谁赢。示例如下:


var p1 = new Promise(function(resolve, reject) {
 setTimeout(resolve, 300, 'p1 doned');
});

var p2 = new Promise(function(resolve, reject) {
 setTimeout(resolve, 50, 'p2 doned');
});

var p3 = new Promise(function(resolve, reject) {
 setTimeout(reject, 100, 'p3 rejected');
});

Promise.race([p1, p2, p3]).then(function(data) {
 // 显然p2更快,所以状态变成了fulfilled
 // 如果p3更快,那么状态就会变成rejected
 console.log(data); // p2 doned
}).catch(function(err) {
 console.log(err); // 不执行
});

Promise.resolve()

Promise.resolve() 接受一个参数值,可以是普通值、具有 then() 方法的对象或 Promise 实例。正常情况下,它返回一个状态为 fulfilled 的 Promise 对象。但是,当解析过程中发生错误时,返回的 Promise 对象状态将置为 rejected。示例如下:


// 参数为普通值
var p4 = Promise.resolve(5);
p4.then(function(data) {
 console.log(data); // 5
});

// 参数为含有then()方法的对象
var obj = {
 then: function() {
  console.log('obj 里面的then()方法');
 }
};

var p5 = Promise.resolve(obj);
p5.then(function(data) {
 // 这里的值时obj方法里面返回的值
 console.log(data); // obj 里面的then()方法
});

// 参数为Promise实例
var p6 = Promise.resolve(7);
var p7 = Promise.resolve(p6);
p7.then(function(data) {
 // 这里的值时Promise实例返回的值
 console.log(data); // 7
});

// 参数为Promise实例,但参数是rejected态
var p8 = Promise.reject(8);
var p9 = Promise.resolve(p8);
p9.then(function(data) {
 // 这里的值时Promise实例返回的值
 console.log('fulfilled:'+ data); // 不执行
}).catch(function(err) {
 console.log('rejected:' + err); // rejected: 8
});

Promise.reject()

Promise.reject() 与 Promise.resolve() 相反,它接收一个参数 reason(异常原因)。此时返回的 Promise 对象状态将直接置为 rejected。示例如下:


var p10 = Promise.reject('手动拒绝');
p10.then(function(data) {
 console.log(data); // 这里不会执行,因为是rejected态
}).catch(function(err) {
 console.log(err); // 手动拒绝
}).then(function(data) {
 // 不受上一级影响
 console.log('状态:fulfilled'); // 状态:fulfilled
});

总之,除非 Promise.then() 方法内部抛出异常或明确置为 rejected 状态,否则它返回的 Promise 状态均为 fulfilled(完成态),且其状态不受上一级状态的影响。

总结与替代方案

总结

常用的方法大致介绍如上,其余方法可根据实际需求进一步了解。

解决 Node.js 回调地狱的方案不仅限于 Promise,还包括 Generator 函数以及 ES7 提出的 Async/Await 实现。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章