ES6 Promise对象详解:状态、链式调用与常用方法

作者:纸飞机时间:2026-10-22 03:19:24浏览:614

本文深入解析ES6中的Promise对象,阐述其作为异步操作代理的核心机制。详细讲解Pending、Resolved和Rejected三种状态转换,演示then方法的链式调用及错误传递特性,并逐一介绍Promise.all、Promise.resolve及catch方法的实际应用场景与注意事项。

本文详细介绍ES6中Promise对象的具体用法,旨在为开发者提供实用的参考与示例。

Promise基本概念与状态机制

1. Promise的基本概念

Promise是一个JavaScript对象,其基本用法与其他对象无异。它主要充当代理(proxy),在异步操作与回调函数之间建立中介机制。通过提供同步操作的接口,Promise使得异步流程具备同步代码的执行逻辑,从而避免了回调函数层层嵌套的问题。

其核心思想在于:每个异步任务立即返回一个Promise实例。由于返回动作是即时的,程序可以沿用同步操作的执行流程。该对象包含一个then方法,用于指定异步任务完成后的回调函数。

假设有一个异步操作f1,它返回一个Promise对象,其对应的回调函数f2的调用方式如下。


(new Promise(f1)).then(f2);

2. Promise的三种状态

Promise对象存在三种可能的状态: ① 异步操作尚未完成(Pending) ② 异步操作已成功完成(Resolved) ③ 异步操作执行失败(Rejected)

3. 运行机制

通过then方法为Promise添加回调函数。该方法可接收两个回调:第一个用于处理状态转为Resolved(成功)的情况,第二个用于处理状态转为Rejected(失败)的情况,其中第二个参数可选。一旦状态发生切换,系统将自动调用相应的回调,并将异步操作的结果或错误作为参数传入。


promise.then(
 console.log,
 console.error
);

then方法的链式调用与错误处理

4. then方法的链式调用

① 由于then方法返回一个新的Promise对象,因此支持链式写法。

② then方法的第一个参数对应Resolved状态的回调,第二个参数(可选)对应Rejected状态的回调。

③ 如下示例所示,当Promise状态变为resolved后,会依次执行后续then指定的回调。每一步操作必须等待前一步执行完毕才会继续。最后一个then中的console.log与console.error存在重要区别:console.log仅显示回调函数step3的返回值,而console.error可以捕获step1、step2或step3中任意环节发生的错误。这表明Promise具有错误传递特性。


promise
 .then(step1)
 .then(step2)
 .then(step3)
 .then(
  console.log,
  console.error
 );

Promise构造函数与Ajax应用

5. Promise的实际应用


var promise = new Promise(function(resolve, reject) { // promise的构造函数,Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject
 // 异步操作的代码
 if (/* 异步操作成功 */){
  resolve(value);//将异步的操作结果作为参数传递出去
 } else {
  reject(error);
 }
});

其中,resolve和reject是两个由JavaScript引擎内置提供的函数,无需开发者自行实现。

resolve函数的作用是将Promise状态从“未完成”(Pending)转变为“成功”(Resolved)。它在异步操作成功时调用,并将操作结果作为参数传递出去。

reject函数的作用是将Promise状态从“未完成”(Pending)转变为“失败”(Rejected)。它在异步操作失败时调用,并将报错信息作为参数传递出去。

① 以下示例展示了使用Promise实现Ajax请求的方法。


var getJSON = function(url) {
 var promise = new Promise(function(resolve, reject){
  var client = new XMLHttpRequest();
  client.open("GET", url);
  client.onreadystatechange = handler;
  client.responseType = "json";
  client.setRequestHeader("Accept", "application/json");
  client.send();
  function handler() {
   if (this.readyState !== 4) {
    return;
   }
   if (this.status === 200) {
    resolve(this.response);//会将参数传递给回调函数
   } else {
    reject(new Error(this.statusText));
   }
  };
 });
 return promise;
};
getJSON("/posts.json").then(function(json) {
 console.log('Contents: ' + json);
}, function(error) {
 console.error('出错了', error);
});

② resolve函数的参数除了常规值外,还可以是另一个Promise实例。这意味着一个异步操作的结果可能是返回另一个异步操作。


var p1 = new Promise(function (resolve, reject) {
 // ...
});
var p2 = new Promise(function (resolve, reject) {
 // ...
 resolve(p1);
})

catch方法捕获错误

6. Promise.prototype.catch()方法

① 如果异步操作抛出错误,Promise状态将变为Rejected,此时会调用catch方法指定的回调函数来处理该错误。


promise.then(function(posts) {
 // ...
}).catch(function(error) {
 // 处理 getJSON 和 前一个回调函数运行时发生的错误
 console.log('发生错误!', error);
});

② 此外,若then方法中指定的回调函数在运行过程中抛出错误,该错误同样会被catch方法捕获。


var promise = new Promise(function(resolve, reject) {
 throw new Error('test');
});
promise.catch(function(error) {
 console.log(error);
});
// Error: test

③ 以下是两种常见的写法示例。


// 写法一
var promise = new Promise(function(resolve, reject) {
 try {
  throw new Error('test');
 } catch(e) {
  reject(e);
 }
});
promise.catch(function(error) {
 console.log(error);
});
// 写法二
var promise = new Promise(function(resolve, reject) {
 reject(new Error('test'));//reject方法的作用,等同于抛出错误
});
promise.catch(function(error) {
 console.log(error);
});

④ 需要注意的是,如果在resolve语句之后抛出错误,该错误不会被捕获。这是因为Promise的状态一旦改变,就会永久保持该状态,不再发生任何变化。


var promise = new Promise(function(resolve, reject) {
 resolve('ok');
 throw new Error('test');
});
promise
 .then(function(value) { console.log(value) })
 .catch(function(error) { console.log(error) });
// ok

Promise.all并发处理

7. Promise.all()方法

该方法接收一个Promise对象的数组作为参数,将多个Promise实例包装成一个新的Promise对象。如果数组中的元素不是Promise对象,系统会自动调用Promise.resolve方法将其转换为Promise实例,再进行后续处理。(注意:Promise.all方法的参数不一定非要是数组,但必须具有Iterator接口,且返回的每个成员都必须是Promise实例)。


var p = Promise.all(promises).then(function (posts) {
 // ...
}).catch(function(reason){
 // ...
});

① 只要promises数组中有一个状态变为rejected,新包装的Promise对象p的状态就会变为rejected,此时第一个被reject的实例的返回值会传递给p的回调函数。 ② 如果所有Promise对象都变为resolved,则promises数组中所有对象的返回值会组成一个数组,传递给p的回调函数。

Promise.resolve对象转换

8. Promise.resolve()方法

该方法用于将现有对象转换为Promise对象,其核心作用即为此。


Promise.resolve('foo')
// 等价于
new Promise(resolve => resolve('foo'))

① 如果参数是一个Promise对象,Promise.resolve()将不做任何处理,直接返回该对象。 ② 如果参数是一个具有then方法的对象(即thenable对象),Promise.resolve方法会将其转换为Promise对象,并立即执行该对象的then方法。


let thenable = {
 then: function(resolve, reject) {
  resolve(42);
 }
};
let p1 = Promise.resolve(thenable);//p1为一个状态已经是resolved 的promise对象.
p1.then(function(value) {
 console.log(value); // 42
});

③ 如果参数不是具有then方法的对象,或者根本不是对象。

该参数将作为生成的Promise对象的resolve()方法的参数。


var p = Promise.resolve('Hello');//Hello 会传递给 p 的resolve()
p.then(function (s){
 console.log(s)
});
// Hello

希望本文的阐述能对大家的ECMAScript程序设计有所帮助。

作者最新文章