Promise对象及相关实例方法介绍

Promise是一种处理异步操作的方法,提供了更好的解决方案。本文详细介绍了Promise的含义、基本用法、then、catch、finally方法,以及Promise.all、Promise.race、Promise.resolve、Promise.reject等实例方法。通过这些方法,可以更好地管理和控制异步操作,使其看起来像同步执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Promise 对象

1.0 Promise 的含义

Promise 是一步编程的一种解决方案, 比传统的解决方案 — 回调函数和事件 — 更合理和更加强大.

所谓 Promise, 简单来说就是一个容器, 里面保存着某个未来才会结束的事件(通常是一个一步操作)的结果.

Promise 对象有以下两个特点.

  1. 对象的状态不受外界影响. Promise 对象代表一个一步操作, 有三种状态: pending , fulfilledrejected . 只有异步操作的结果, 可以决定当前是哪一种状态, 其他任何操作都无法改变这个状态.
  2. 一旦状态改变, 就不会再变, 任何时候都可以得到这个结果. Promise 对象的状态改变, 只有两种可能: 从 pending 变为 fulfilled 和从 pending变为rejected. 这要这两种情况发生, 状态就凝固了, 不会再改变了, 会一直保持这个结果, 这时就称为 resolved(已定性). 如果改变已经发生了, 你再对 promise 对象添加回调函数, 也会立即得到这个结果. 这与事件完全不同, 事件的特点就是, 如果你错过了它, 你再去监听,是得不到结果的.

有了 Promise 对象, 就可以将异步的操作 以 同步的流程表达出来., 避免了层层嵌套函数. 此外, Promise 对象提供统一的接口,使得控制异步操作更加容易.

Promise 也有一些缺点,:

  • 首先, 无法取消 Promise, 一旦新建它就会立即执行, 无法取消.
  • 其次, 如果不设置回调函数, Promise 内部抛出的错误, 不会反映到外部.
  • 第三, 当处于 pending 状态时, 无法得知目前进展到哪一个阶段(即: 无法得知是刚刚开始还是即将完成).

2.0 基本用法

ES6 规定, promise 对象是一个构造函数, 用来生成 Promise 实例.

下面代码创造了一个 Promise 实例

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

Promise 构造函数接收一个函数作为参数, 该函数的两个参数分别是 resolvereject. 它们是两个函数, 有JavaScript 引擎提供, 不用自己部署.

resolve 函数的作用是, 将 Promise 对象的状态从"未完成" 变为 “成功”(即从 pending 变为 resolved), 在异步操作成功时调用, 并将异步操作的结果, 作为参数传递出去.

reject 函数的作用是, 将 Promise 对象的状态从 “未完成” 变为 “失败” (即从 pending 变为 rejected), 在异步操作失败时调用, 并将异步操作爆出的错误, 作为参数传递出去.

Promise 实例生成以后, 可以用 then 方法分别指定 resolved 状态和 rejected 状态的回调函数.

promise.then((value)=>{
    // success
},(error)=>{
    // failure
})

then 方法可以接收两个回调函数作为参数,:

  • 第一个回调函数是 Promise 对象的状态变为 resolved 时调用
  • 第二个回调函数是 Promise 对象的状态变为 rejected 时调用.

其中, 第二个函数是可选的, 不一定要提供. 这两个函数都接受 Promise 对象传出的值作为参数.

下面是一个 Promise 对象的简单例子.

function timeout(ms) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms, 'done'); // 把 'done' 结果传给 resolve 函数.
  });
}

timeout(100).then((value) => {
  console.log(value); // done
});

🏴 注意: setTimeout函数理解

var timeoutID = scope.setTimeout(function[, delay, arg1, arg2, ...]);
var timeoutID = scope.setTimeout(function[, delay]); 
var timeoutID = scope.setTimeout(code[, delay]);

// 参数理解
  function: 是你想要在到期时间之后执行的函数
  delay:  可选, 延迟的时间
  arg1, ... , argN: 可选, 附件参数, 一旦定时器到期, 它们会作为参数传递给 `function` 
  
#  代码演示如下 ----------------------

setTimeout(function (value1, value2, value3) {
    console.log(value1,value2, value3); // 参数一 参数2 参数三
}, 1000, '参数一', '参数2','参数三')

上面代码中, timeout 方法返回一个 Promise 实例, 表示一段时间以后才会发生的结果. 过了指定的时间 (ms参数)以后, Promise 实例的状态变为 resolved, 就会触发 then 方法绑定的回调函数.

Promise 新建后会立即执行.

let promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
});

promise.then(function() {
  console.log('resolved.');
});

console.log('Hi!');

// Promise
// Hi!
// resolved

上面代码中,Promise 新建后立即执行,所以首先输出的是Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出

3.0 Promise.prototype.then()

Promise 实例具有 then 方法, 也就是说, then方法是定义在原型对象Promise.prototype 上的. 它 的作用是为 Promise实例添加状态改变时的回调函数. 前面说过, then 方法 的 第一个参数是 resolved 状态对应的回调函数, 第二个参数(可选) 是 rejected 状态对应的回调函数.

then方法返回的是一个新的 Promise 实例.(注意, 不是原来那个Promise实例), 因此可以采用链式写法, 即 then 方法后面再调用另一个 then 方法.

getJSON("/posts.json").then(function(json) {
  return json.post;
}).then(function(post) {
  // ...
});

上面的代码使用then方法,依次指定了两个回调函数。第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。

4.0 Promise.prototype.catch()

Promise.prototype.catch() 方法是 `.then(null,rejection) 或.then(undefined,rejection)的别名, 用于指定发生错误时的回调函数.

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

上面代码中,getJSON()方法返回一个 Promise 对象,如果该对象状态变为resolved,则会调用then()方法指定的回调函数;如果异步操作抛出错误,状态就会变为rejected,就会调用catch()方法指定的回调函数,处理这个错误。另外,then()方法指定的回调函数,如果运行中抛出错误,也会被catch()方法捕获。

5.0 Promise.prototype.finally()

finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。

promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});

上面代码中,不管promise最后的状态,在执行完thencatch指定的回调函数以后,都会执行finally方法指定的回调函数。

finally方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是fulfilled还是rejected。这表明,finally方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。

6.0 Promise.all()

Promise.all() 方法用于将多个 Promise 实例, 包装成一个新的 Promise实例.

const p = Promise.all([p1, p2, p3]);

上面代码中,Promise.all()方法接受一个数组作为参数,p1p2p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。

p的状态由p1p2p3决定,分成两种情况。

(1)只有p1p2p3的状态都变成fulfilledp的状态才会变成fulfilled,此时p1p2p3的返回值组成一个数组,传递给p的回调函数。

(2)只要p1p2p3之中有一个被rejectedp的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

7.0 Promise.race()

Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。

const p = Promise.race([p1, p2, p3]);

上面代码中,只要p1p2p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

8.0 Promise.resolve()

有时需要将现有的对象转换为 Promise 对象, Promise.resolve() 方法就起到了作用

const jsPromise = Promise.resolve($.ajax('/whatever.json'));

上面代码将jQuery 生成的 deferred 对象, 转为一个新的 Promise` 对象.

Promise.resolve() 等价于下面的写法

Promise.resolve('foo')
// 等价于
new Promise(resolve =>resolve('foo'))
  1. 参数是一个 Promise实例

    如果参数是一个Promise实例, 那么Promise.resolve 将不做任何修改, 原封不懂返回这个实例.

  2. 参数是一个 thenable对象

    thenable 对象指的是具有 then 方法的对象, 比如下面这个对象

    let thenable = {
      then: function(resolve, reject) {
        resolve(42);
      }
    };
    

    Promise.resolve 方法会将这个对象转为 Promise 对象, 然后就立即执行 thenable 对象的 then 方法

    let thenable = {
      then: function(resolve, reject) {
        resolve(42);
      }
    };
    
    let p1 = Promise.resolve(thenable);
    p1.then(function(value) {
      console.log(value);  // 42
    });
    

    上面代码中,thenable对象的then方法执行后,对象p1的状态就变为resolved,从而立即执行最后那个then方法指定的回调函数,输出 42。

  3. 参数不是具有then方法的对象, 或根本就不是对象

如果参数是一个原始值, 或者是一个不具有 then 方法的对象, 则 Promise.resolve 方法返回一个新的Promise 对象, 状态为 resolved .

const p = Promise.resolve('Hello');

p.then(function (s){
  console.log(s)
});
// Hello

上面代码生成一个新的 Promise 对象的实例p。由于字符串Hello不属于异步操作(判断方法是字符串对象不具有 then 方法),返回 Promise 实例的状态从一生成就是resolved,所以回调函数会立即执行。Promise.resolve方法的参数,会同时传给回调函数。

  1. 不带有任何参数

Promise.resolve() 方法允许调用时不带参数, 直接返回一个 resolved 状态的 Promise 对象.

所以, 如果希望得到一个 Promise 对象, 比较方便的方法就是直接调用 Promise.resolve()方法.

const p = Promise.resolve();

p.then(function () {
  // ...
});

上面代码的变量p就是一个 Promise 对象。

需要注意的是,立即resolve()的 Promise 对象,是在本轮“事件循环”(event loop)的结束时执行,而不是在下一轮“事件循环”的开始时。

setTimeout(function () {
  console.log('three');
}, 0);

Promise.resolve().then(function () {
  console.log('two');
});

console.log('one');

// one
// two
// three

上面代码中,setTimeout(fn, 0)在下一轮“事件循环”开始时执行,Promise.resolve()在本轮“事件循环”结束时执行,console.log('one')则是立即执行,因此最先输出。

9.0 Promise.rejected()

Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected

const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了'))

p.then(null, function (s) {
  console.log(s)
});
// 出错了

上面代码生成一个 Promise 对象的实例p,状态为rejected,回调函数会立即执行。

注意,Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。这一点与Promise.resolve方法不一致。

const thenable = {
  then(resolve, reject) {
    reject('出错了');
  }
};

Promise.reject(thenable)
.catch(e => {
  console.log(e === thenable)
})
// true

上面代码中,Promise.reject方法的参数是一个thenable对象,执行以后,后面catch方法的参数不是reject抛出的“出错了”这个字符串,而是thenable对象。

总结:

上一章: ES6 Reflect 介绍, Reflect 相关方法介绍

下一章: Generator 函数语法, yield 表达式, next()方法理解

交流学习添加微信(备注技术交流学习): Gene199302
在这里插入图片描述

该博客为学习阮一峰 ES6入门课所做的笔记记录, 仅用来留作笔记记录和学习理解

<think>我们正在讨论JavaScript中的Promise对象,特别是静态方法实例方法的区别及用法。根据提供的引用,我们可以总结如下:###实例方法实例方法是定义在Promise原型上的方法,需要通过Promise实例来调用。常见的实例方法包括:1.`Promise.prototype.then(onFulfilled,onRejected)`:用于添加处理Promise状态改变的回调函数。当Promise被解决(fulfilled)时调用`onFulfilled`,被拒绝(rejected)时调用`onRejected`。它返回一个新的Promise,因此可以链式调用。2.`Promise.prototype.catch(onRejected)`:用于处理Promise被拒绝的情况,相当于`.then(null,onRejected)`。3.`Promise.prototype.finally(onFinally)`:无论Promise最终状态如何,都会执行的回调函数。它不接收任何参数,通常用于清理操作。###静态方法静态方法是直接定义在Promise构造函数上的方法,不需要实例就可以调用。它们用于处理多个Promise或创建Promise。常见的静态方法包括:1.`Promise.resolve(value)`:返回一个以给定值解决的Promise。如果参数是Promise,则直接返回该Promise;如果参数是thenable对象(具有then方法对象),则返回的Promise会跟随该thenable对象的状态;否则返回一个以该参数解决的Promise[^3]。2.`Promise.reject(reason)`:返回一个以给定原因拒绝的Promise。3.`Promise.all(iterable)`:接受一个可迭代对象(如数组)的Promise,返回一个新的Promise。当所有输入的Promise都解决时,新Promise才解决,解决值为所有Promise解决值的数组;如果有一个输入Promise被拒绝,则新Promise立即被拒绝,拒绝原因为第一个被拒绝的Promise的原因[^1]。4.`Promise.race(iterable)`:同样接受一个可迭代对象Promise,返回一个新的Promise。新Promise的状态由第一个完成(无论是解决还是拒绝)的输入Promise决定[^4]。5.`Promise.allSettled(iterable)`:当所有输入的Promise都已解决或拒绝(即每个Promise都已敲定)时,返回的Promise才解决,解决值为描述每个Promise结果的对象数组。6.`Promise.any(iterable)`:当输入中有一个Promise解决时,返回的Promise就解决,解决值为该Promise的解决值;如果所有Promise都被拒绝,则返回的Promise被拒绝,拒绝原因是一个AggregateError,包含所有拒绝原因。###区别1.**调用方式**:实例方法实例调用(如`promise.then()`),静态方法由构造函数调用(如`Promise.resolve()`)。2.**功能**:实例方法主要用于单个Promise的状态处理(链式调用),而静态方法主要用于多个Promise的组合或创建新的Promise。3.**返回值**:实例方法通常返回新的Promise,便于链式调用;静态方法也返回新的Promise,但其行为取决于多个输入Promise的状态。###使用场景-**实例方法**:当你有一个Promise对象,并需要处理它的结果(成功、失败或无论成功失败都要执行的操作)时使用。-**静态方法**:-`Promise.resolve()`/`Promise.reject()`:快速创建已解决或已拒绝的Promise。-`Promise.all()`:当需要等待多个异步操作都成功完成时(如并行请求多个接口,等所有数据都返回再渲染页面)。-`Promise.race()`:用于超时控制或获取最快响应的场景(如设置请求超时时间)。-`Promise.allSettled()`:当需要知道多个异步操作各自的结果(无论成功或失败)时(如批量操作后需要汇总结果)。-`Promise.any()`:当需要获取多个异步操作中第一个成功的操作结果时(如从多个镜像源下载同一个文件,只要有一个成功即可)。###示例代码```javascript//实例方法示例constpromise=newPromise((resolve,reject)=>{setTimeout(()=>resolve('success'),1000);});promise.then(result=>console.log(result))//输出:success.catch(error=>console.error(error)).finally(()=>console.log('done'));//静态方法示例:Promise.allconstp1=Promise.resolve(1);constp2=newPromise((resolve)=>setTimeout(resolve,100,2));constp3=3;//非Promise值会被Promise.resolve转换Promise.all([p1,p2,p3]).then(values=>console.log(values));//输出:[1,2,3]//静态方法示例:Promise.raceconstp4=newPromise(resolve=>setTimeout(resolve,500,'slow'));constp5=newPromise(resolve=>setTimeout(resolve,100,'fast'));Promise.race([p4,p5]).then(value=>console.log(value));//输出:'fast'```§§相关问题§§1.如何手动实现`Promise.all`方法?2.`Promise.prototype.finally`方法在链式调用中的行为是怎样的?3.在什么场景下应该使用`Promise.any`而不是`Promise.race`?4.`Promise.resolve`和`newPromise(resolve=>resolve(value))`有什么区别?</think>### JavaScript Promise 静态方法 vs 实例方法详解 #### 一、核心区别 | 特性 | 实例方法 | 静态方法 | |--------------|------------------------------------|------------------------------------| | **调用方式** | 通过Promise实例调用<br>(如`promise.then()`) | 直接通过构造函数调用<br>(如`Promise.all()`) | | **作用对象** | 操作单个Promise实例 | 操作多个Promise实例或创建新Promise | | **返回值** | 返回新Promise(支持链式调用) | 返回新Promise | | **典型方法** | `then()`, `catch()`, `finally()` | `all()`, `race()`, `resolve()`, `reject()` | #### 二、实例方法详解 1. **`then(onFulfilled, onRejected)`** - 处理Promise的解决(fulfilled)或拒绝(rejected)状态 - 返回新Promise,支持链式调用 ```javascript fetchData() .then(response => process(response)) // 成功处理 .then(data => console.log(data)) .catch(error => handleError(error)); // 失败处理 ``` 2. **`catch(onRejected)`** - 专门处理拒绝状态(等价于`.then(null, onRejected)`) - 捕获链式调用中任何位置的错误 ```javascript getUser() .then(user => getPosts(user.id)) .catch(err => console.error("请求失败:", err)); // 捕获所有错误 ``` 3. **`finally(onFinally)`** - 无论成功/失败都会执行,适用于清理操作 ```javascript loadData() .then(render) .catch(showError) .finally(() => hideLoader()); // 始终隐藏加载器 ``` #### 三、静态方法详解 1. **`Promise.all(iterable)`** - **场景**:需等待所有异步操作完成(如并行请求) - **规则**:全部成功时返回结果数组;任意失败立即拒绝[^1] ```javascript Promise.all([fetchUsers(), fetchProducts()]) .then(([users, products]) => renderDashboard(users, products)) .catch(err => console.error("部分请求失败", err)); ``` 2. **`Promise.race(iterable)`** - **场景**:获取最快响应的操作(如超时控制) - **规则**:返回第一个完成(成功/失败)的结果[^4] ```javascript Promise.race([ fetchData(), new Promise((_, reject) => setTimeout(() => reject(new Error("超时")), 5000) ) ]).then(data => useData(data)); ``` 3. **`Promise.resolve(value)`** - 创建已解决的Promise,支持转换thenable对象 ```javascript // 将同步值转为Promise Promise.resolve(42) .then(val => val * 2); // 84 // 转换thenable对象 const thenable = { then(resolve) { resolve("转换") } }; Promise.resolve(thenable).then(console.log); // "转换"[^3] ``` 4. **`Promise.reject(reason)`** - 创建立即拒绝的Promise ```javascript Promise.reject(new Error("失败")) .catch(err => console.log(err.message)); // "失败" ``` #### 四、关键使用场景对比 | 场景 | 推荐方法 | 原因 | |--------------------------|------------------|----------------------------------------------------------------------| | 顺序异步操作 | `then()`链式调用 | 清晰表达操作依赖关系 | | 并行独立请求 | `Promise.all()` | 确保所有数据就绪再处理 | | 请求超时控制 | `Promise.race()` | 快速响应最先返回的结果 | | 错误集中处理 | `catch()` | 避免在每个`then()`中重复错误处理 | | 清理资源(如关闭加载动画)| `finally()` | 无论成功失败都需执行 | | 将同步值转为Promise | `Promise.resolve()` | 统一异步接口处理 | #### 五、注意事项 1. **链式调用中断**:在`then()`中抛出错误会跳过后续链式调用,直接触发`catch()` 2. **状态不可逆**:Promise状态一旦改变(fulfilled/rejected)不可逆转 3. **错误吞噬**:未处理的拒绝可能导致静默失败,始终添加`catch()` 4. **性能陷阱**:`Promise.all()`在大量请求时可能阻塞,需结合分页/流处理 > 关键原则:实例方法操作**单个**Promise的生命周期,静态方法处理**多个**Promise的协调关系或创建新Promise
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值