Promise静态方法解析

本专栏聚焦Promise的核心原理与高级应用,包含: ✓ Promise A+规范深度解读 ✓ 手写实现与源码分析 ✓ 异步编程设计模式 ✓ 性能调优与错误处理
适合有JavaScript基础,希望深入异步编程的开发者。我们将用最少的篇幅,讲透最核心的知识。

引言:Promise静态方法

在之前的文章中,我们探讨了Promise的状态机制和实例方法。本篇文章将介绍Promise的静态方法,即:直接通过Promise类调用的方法。我将这些方法分成了两个大类,一类是创建类方法,一类是控制类方法:

  • 创建类方法:创建Promise的多种方式,主要分为三种: Promise构造函数Promise.resolve()Promise.reject()

  • 控制类方法:本质是管理控制多个Promise,并使其能协调工作,主要包括:Promise.all()Promise.race()Promise.allSettled()Promise.any()

创建类方法

Promise构造函数

Promise构造函数的基本语法

Promise构造函数是创建Promise对象的根本方法,它将回调的异步操作包装为Promise,其基本语法如下:

javascript 复制代码
const myPromise = new Promise((resolve, reject) => {})

上述代码创建了一个空的Promise对象,我们在创建Promise时,也可以进行一些初始化操作,如以下代码所示:

javascript 复制代码
const myPromise = new Promise((resolve, reject) => {
    // 这个函数会立即执行
    console.log('executor开始执行');

    // 异步操作
    setTimeout(() => {
        const success = Math.random() > 0.5;

        if (success) {
            resolve('操作成功');
        } else {
            reject(new Error('操作失败'));
        }
    }, 1000);

    console.log('executor执行完毕');
});

console.log('Promise已创建,状态:', myPromise);

这段代码的执行结果是:

bash 复制代码
executor开始执行
executor执行完毕
Promise已创建,状态: Promise { <pending> }

从结果中可以看出,此时的Promise状态一直为pending

构造函数的三大特性

立即执行

Promise构造函数中的同步代码会立即执行,而异步代码不会执行。

javascript 复制代码
console.log('开始');
const myPromise = new Promise((resolve, reject) => {
    console.log('executor执行中...');
    resolve('完成');
});
console.log('结束');

上述代码的执行结果是:

javascript 复制代码
开始
executor执行中...
结束
resolve/reject只能调用一次

由于Promise的状态机制,Promise中的resolve/reject只能调用一次,多个resolve/reject会被自动忽略,不会执行:

javascript 复制代码
const myPromise = new Promise((resolve, reject) => {
    resolve('第一次调用有效');
    resolve('第二次调用被忽略'); // 无效
    reject(new Error('这个也被忽略')); // 无效
});
异常自动转换为reject
javascript 复制代码
const p = new Promise((resolve, reject) => {
    throw new Error('执行器异常'); // 自动调用reject
    // 等同于:reject(new Error('执行器异常'))
});

Promise.resolve()

Promise.resolve() 方法用于创建一个状态为 fulfilled 的Promise对象,它其实和 new Promise((resolve, reject) => resolve()) 这段代码等价。使用这个方法,实际上可以把任意值都转成一个Promise,有4种处理模式:

包装普通值

javascript 复制代码
const p1 = Promise.resolve('hello');  // Promise<fulfilled: 'hello'>

当有多个值的时候,Promise会怎么处理呢?

javascript 复制代码
const p2 = Promise.resolve('hello', 'world');  // Promise<fulfilled: 'hello'>

在这种情况下,Promise.resolve()只会处理第一个参数,而把后面的参数全部忽略掉,即上述两段代码中p1和p2是等价的:p1 === p2 // true

包装thenable对象

javascript 复制代码
const thenable = {
    then: function(onFulfilled, onRejected) {
        setTimeout(() => onFulfilled('thenable的结果'), 100);
    }
};
const p = Promise.resolve(thenable);

包装异步值

javascript 复制代码
async function asyncFunc() {
    return 'async返回值';
}
const p = Promise.resolve(asyncFunc());

包装Promise对象

javascript 复制代码
const originalPromise = new Promise(resolve => 
    setTimeout(() => resolve('原始值'), 200)
);

const p = Promise.resolve(originalPromise);
console.log(p === originalPromise); // true,是同一个对象

对于这段代码,我们可以看到,poriginalPromise 居然也是等价,这又是为什么呢? 原来,当 Promise.resolve() 方法中,接收到一个Promise参数时,那它的行为就类似一个空包装,因此我们也可以是 Promise.resolve() 方法是一个幂等方法,即:

javascript 复制代码
const p = Promise.resolve(1);
console.log(p === Promise.resolve(Promise.resolve(Promise.resolve(p))));

上述代码里面无论包多少层Promise.resolve() 方法,其结果永远为true。

Promise.reject()

这个方法和 Promise.resolve() 方法对应,用于创建一个 rejected 状态的Promise实例,并抛出一个异步错误。

注:Promise.resolve() 方法抛出异步错误时,是无法使用try/catch进行捕获的。

Promise.reject() 方法和 Promise.resolve() 方法基本类似,本文不再赘述,唯一要注意的点是:Promise.reject() 方法并没有照搬 Promise.resolve() 方法的幂等逻辑,如果给Promise.reject() 方法传递一个Promise参数,则这个Promise参数会成为它返回的拒绝原因。

控制类方法

所谓控制类方法,其实就是Promise提供的将多个Promise实例,组合成一个Promise实例的静态方法,合成后的Promise行为取决于内部约定的行为。

Promise.all()

Promise.all() 方法创建的Promise,会在所有Promise全部解决后,再解决,即:只要中间有一个Promise状态为 rejected ,则最终结果为rejected 。当有多个Promise状态都为 rejected 时,则第一个状态为 rejected 的Promise实例,会将自己的理由作为最终的拒绝理由。我们来看看下面一个例子:

javascript 复制代码
const fastReject = new Promise((resolve, reject) => {
    setTimeout(() => reject("快速失败"), 10);
});

const slowReject = new Promise((resolve, reject) => {
    setTimeout(() => reject("慢速失败"), 100);
});

const fastResolve = new Promise((resolve) => {
    setTimeout(() => resolve("快速成功"), 50);
});

Promise.all([fastReject, slowReject, fastResolve])
    .then((results) => {
        console.log("所有 Promise 都成功了:", results);
    })
    .catch((error) => {
        console.log("Promise.all() 失败:", error);
    });

上述代码输出结果是:Promise.all() 失败: 快速失败

Promise.allSettled()

Promise.allSettled() 是ES2020新增的方法,它等待所有Promise完成(无论成功或失败),然后报告每个Promise的结果。相比于 Promise.all() 方法,Promise.allSettled() 更像一个记录员,记录每个Promise的结果。我们来看看下面一个例子:

javascript 复制代码
// 创建三个 Promise
const p1 = Promise.resolve("成功1");
const p2 = Promise.reject("失败2");
const p3 = new Promise((resolve) => {
    setTimeout(() => resolve("成功3"), 1000);
});

// 使用 Promise.allSettled()
Promise.allSettled([p1, p2, p3])
    .then((results) => {
        console.log("所有 Promise 都已解决:");
        results.forEach((result, index) => {
            console.log(`p${index + 1}:`, result);
        });
    });

上述代码的输出结果是:

bash 复制代码
所有 Promise 都已解决:
p1: { status: 'fulfilled', value: '成功1' }
p2: { status: 'rejected', reason: '失败2' }
p3: { status: 'fulfilled', value: '成功3' }

Promise.race()

Promise.race() 返回最先完成的Promise(无论成功还是失败)的结果。我们来看看下面一个例子:

javascript 复制代码
// 创建一个可能会长时间运行的 Promise
function longTask(duration = 3000) {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(`长时间任务完成(耗时 ${duration}ms)`);
        }, duration);
    });
}

// 创建一个超时 Promise
function timeout(ms) {
    return new Promise((_, reject) => {
        setTimeout(() => {
            reject(`操作超时(${ms}ms)`);
        }, ms);
    });
}


Promise.race([longTask(3000), timeout(2000)])
    .then((result) => {
        console.log("成功:", result);
    })
    .catch((error) => {
        console.log("失败:", error); 
    });

上述代码的执行结果是:失败: 操作超时(2000ms)

Promise.any()

Promise.any() 是ES2021新增的方法,它返回第一个成功的Promise,只有当所有Promise都失败时才失败。我们来看看下面一个例子:

javascript 复制代码
const successFast = new Promise((resolve) => {
    setTimeout(() => resolve("快速成功"), 100);
});

const successSlow = new Promise((resolve) => {
    setTimeout(() => resolve("慢速成功"), 1000);
});

const failure = new Promise((_, reject) => {
    setTimeout(() => reject("失败"), 50);
});

// 即使有失败的 Promise,只要有一个成功就行
Promise.any([failure, successFast, successSlow])
    .then((result) => {
        console.log("成功:", result);
    })
    .catch((error) => {
        console.log("全部失败:", error);
    });

上述代码的输出结果是:成功: 快速成功

结语

本文主要介绍了Promise的几种静态方法,对于文章中错误的地方或者有任何问题,欢迎在评论区留言讨论!

相关推荐
持续升级打怪中11 小时前
ES6 Promise 完全指南:从入门到精通
前端·javascript·es6
AC赳赳老秦11 小时前
前端可视化组件开发:DeepSeek辅助Vue/React图表组件编写实战
前端·vue.js·人工智能·react.js·信息可视化·数据分析·deepseek
小白冲鸭11 小时前
苍穹外卖-前端环境搭建-nginx双击后网页打不开
运维·前端·nginx
wulijuan88866611 小时前
Web Worker
前端·javascript
深念Y11 小时前
仿B站项目 前端 3 首页 整体结构
前端·ai·vue·agent·bilibili·首页
IT_陈寒11 小时前
React 18实战:这5个新特性让我的开发效率提升了40%
前端·人工智能·后端
深念Y12 小时前
仿B站项目 前端 5 首页 标签栏
前端·vue·ai编程·bilibili·标签栏·trae·滚动栏
克里斯蒂亚诺更新12 小时前
vue3使用pinia替代vuex举例
前端·javascript·vue.js
Benny的老巢12 小时前
用 Playwright 启动指定 Chrome 账号的本地浏览器, 复用原账号下的cookie信息
前端·chrome
2501_9418053112 小时前
从微服务网关到统一安全治理的互联网工程语法实践与多语言探索
前端·python·算法