一般情况下,new Promise 应该传入两个参数。我不喜欢省略的模式。

Promise 构造函数中,确实通常会传入一个带有两个参数的回调函数,这两个参数分别是 resolverejectresolve 用于将 Promise 状态从 pending(进行中)变为 fulfilled(已成功),reject 则用于将其状态从 pending 变为 rejected(已失败)。

在之前给出的示例中,只使用了 resolve 而没有使用 reject,这是因为示例的目的是模拟一个只会成功不会失败的异步操作。不过在实际开发里,很多异步操作是可能会失败的,所以需要使用 reject 来处理错误情况。

下面是一个同时使用 resolvereject 的示例:

javascript 复制代码
example.ts
Apply
function asyncOperationWithError(): Promise<void> {
    return new Promise((resolve, reject) => {
        // 模拟一个可能失败的异步操作,这里用 Math.random 来随机决定是否成功
        const randomNumber = Math.random();
        setTimeout(() => {
            if (randomNumber < 0.5) {
                console.log('异步操作成功');
                resolve();
            } else {
                console.log('异步操作失败');
                reject(new Error('异步操作失败'));
            }
        }, 2000);
    });
}

async function main() {
    console.log('开始异步操作');
    try {
        await asyncOperationWithError();
        console.log('异步操作已成功结束');
    } catch (error) {
        console.error('异步操作出错:', error);
    }
}

main();

代码解释

  1. asyncOperationWithError 函数

    • 创建了一个 Promise,其回调函数接收 resolvereject 两个参数。
    • 使用 Math.random() 生成一个 0 到 1 之间的随机数,如果这个数小于 0.5,就认为异步操作成功,调用 resolve();否则认为操作失败,调用 reject() 并传入一个 Error 对象。
  2. main 函数

    • 这是一个异步函数,使用 try...catch 块来处理 asyncOperationWithError 可能抛出的错误。
    • 如果 asyncOperationWithError 成功(Promise 状态变为 fulfilled),则打印 异步操作已成功结束;如果失败(Promise 状态变为 rejected),则在 catch 块中捕获错误并打印错误信息。

所以,当你处理可能失败的异步操作时,通常要同时传入 resolvereject 来分别处理成功和失败的情况。


以下是一个有返回值的 Promise 示例,在这个示例中,我们会模拟一个异步的数据库查询操作,该操作会返回查询到的数据。

javascript 复制代码
example.ts
Apply
// 模拟数据库查询,返回一个 Promise,该 Promise 会在 2 秒后返回查询结果
function queryDatabase(): Promise<string[]> {
    return new Promise((resolve, reject) => {
        // 模拟 2 秒的查询延迟
        setTimeout(() => {
            const success = Math.random() < 0.8;
            if (success) {
                // 模拟查询成功,返回一个字符串数组作为查询结果
                const result: string[] = ['data1', 'data2', 'data3'];
                resolve(result);
            } else {
                // 模拟查询失败,返回一个错误信息
                reject(new Error('数据库查询失败'));
            }
        }, 2000);
    });
}

// 调用数据库查询函数,并处理结果
async function main() {
    console.log('开始查询数据库');
    try {
        const data = await queryDatabase();
        console.log('查询成功,结果如下:', data);
    } catch (error) {
        console.error('查询出错:', error);
    }
}

// 启动主函数
main();

代码解释

  1. queryDatabase 函数

    • 该函数返回类型为 Promise<string[]>,表示它会返回一个 Promise,当这个 Promise 成功解决时,会返回一个字符串数组。
    • Promise 的回调函数中,使用 setTimeout 模拟 2 秒的查询延迟。
    • 通过 Math.random() < 0.8 来模拟查询成功的概率(80% 的成功率)。
    • 如果成功,使用 resolve(result) 将查询结果(一个字符串数组)传递出去;如果失败,使用 reject(new Error('数据库查询失败')) 抛出一个错误。**
  2. main 函数

    • 这是一个异步函数,使用 await 关键字来等待 queryDatabase 函数返回的 Promise 被解决。
    • 使用 try...catch 块来处理可能出现的错误。如果查询成功,将查询结果打印到控制台;如果查询失败,捕获错误并打印错误信息。

通过这种方式,我们可以处理有返回值的异步操作,并对可能出现的错误进行捕获和处理。


以下是一个包含两个 Promise 嵌套,且第二个 Promise 接收第一个 Promise 结果的 TypeScript 示例:

typescript 复制代码
example.ts
Apply
// 第一个 Promise 函数,模拟异步获取用户 ID
function getUserID(): Promise<number> {
    return new Promise((resolve, reject) => {
        // 模拟异步操作,如网络请求
        setTimeout(() => {
            const success = Math.random() < 0.8;
            if (success) {
                // 模拟成功获取用户 ID
                const userID = 123;
                resolve(userID);
            } else {
                // 模拟获取失败
                reject(new Error('获取用户 ID 失败'));
            }
        }, 1500);
    });
}

// 第二个 Promise 函数,接收用户 ID 并模拟异步获取用户信息
function getUserInfo(userID: number): Promise<{ name: string; age: number }> {
    return new Promise((resolve, reject) => {
        // 模拟异步操作,如根据用户 ID 从数据库获取用户信息
        setTimeout(() => {
            const success = Math.random() < 0.8;
            if (success) {
                // 模拟成功获取用户信息
                const userInfo = { name: 'John Doe', age: 30 };
                resolve(userInfo);
            } else {
                // 模拟获取失败
                reject(new Error(`获取用户 ID 为 ${userID} 的信息失败`));
            }
        }, 1500);
    });
}

// 主函数,调用上述两个 Promise 函数
async function main() {
    try {
        console.log('开始获取用户 ID...');
        const userID = await getUserID();
        console.log(`成功获取用户 ID: ${userID},开始获取用户信息...`);
        const userInfo = await getUserInfo(userID);
        console.log('成功获取用户信息:', userInfo);
    } catch (error) {
        console.error('操作出错:', error);
    }
}

// 启动主函数
main();

代码解释:

  1. getUserID 函数

    • 该函数返回一个 Promise<number>,表示会返回一个 Promise,当 Promise 成功时,会返回一个 number 类型的用户 ID。
    • 使用 setTimeout 模拟一个异步操作,有 80% 的概率成功获取用户 ID,若成功则调用 resolve 并传入用户 ID;若失败则调用 reject 并传入错误信息。
  2. getUserInfo 函数

    • 该函数接收一个 number 类型的 userID 参数,返回一个 Promise<{ name: string; age: number }>,表示返回的 Promise 成功时会得到一个包含用户姓名和年龄的对象。
    • 同样使用 setTimeout 模拟异步操作,根据传入的 userID 去获取用户信息,有 80% 的概率成功,成功时调用 resolve 并传入用户信息对象,失败时调用 reject 并传入错误信息。
  3. main 函数

    • 这是一个异步函数,使用 await 关键字来按顺序执行 getUserIDgetUserInfo 函数。
    • 先调用 getUserID 函数获取用户 ID,若成功则接着使用该用户 ID 调用 getUserInfo 函数获取用户信息。
    • 使用 try...catch 块捕获可能出现的错误并打印错误信息。

通过这种方式,实现了两个 Promise 的嵌套,并且第二个 Promise 接收了第一个 Promise 的结果。

以下是使用老式的 Promise 链式调用方式(即将第二个 Promise 写在第一个 Promiseresolve 回调里)来实现相同功能的示例代码:

typescript 复制代码
example.ts
Apply
// 第一个 Promise 函数,模拟异步获取用户 ID
function getUserID(): Promise<number> {
    return new Promise((resolve, reject) => {
        // 模拟异步操作,如网络请求
        setTimeout(() => {
            const success = Math.random() < 0.8;
            if (success) {
                // 模拟成功获取用户 ID
                const userID = 123;
                resolve(userID);
            } else {
                // 模拟获取失败
                reject(new Error('获取用户 ID 失败'));
            }
        }, 1500);
    });
}

// 第二个 Promise 函数,接收用户 ID 并模拟异步获取用户信息
function getUserInfo(userID: number): Promise<{ name: string; age: number }> {
    return new Promise((resolve, reject) => {
        // 模拟异步操作,如根据用户 ID 从数据库获取用户信息
        setTimeout(() => {
            const success = Math.random() < 0.8;
            if (success) {
                // 模拟成功获取用户信息
                const userInfo = { name: 'John Doe', age: 30 };
                resolve(userInfo);
            } else {
                // 模拟获取失败
                reject(new Error(`获取用户 ID 为 ${userID} 的信息失败`));
            }
        }, 1500);
    });
}

// 主函数,调用上述两个 Promise 函数
function main() {
    getUserID()
      .then((userID) => {
            console.log(`成功获取用户 ID: ${userID},开始获取用户信息...`);
            return getUserInfo(userID);
        })
      .then((userInfo) => {
            console.log('成功获取用户信息:', userInfo);
        })
      .catch((error) => {
            console.error('操作出错:', error);
        });
}

// 启动主函数
main();

代码解释:

  1. getUserID 函数

    • 此函数返回一个 Promise<number>,使用 setTimeout 模拟异步操作来获取用户 ID。以 80% 的概率成功获取用户 ID,成功时调用 resolve 并传入用户 ID,失败时调用 reject 并传入错误信息。
  2. getUserInfo 函数

    • 该函数接收一个 number 类型的 userID 参数,返回一个 Promise<{ name: string; age: number }>。同样使用 setTimeout 模拟根据用户 ID 获取用户信息的异步操作,以 80% 的概率成功获取,成功时调用 resolve 并传入用户信息对象,失败时调用 reject 并传入错误信息。
  3. main 函数

    • 调用 getUserID 函数,使用 .then 方法处理其返回的 Promise
    • 在第一个 .then 回调中,接收 getUserID 成功返回的用户 ID,打印相应信息,然后调用 getUserInfo 函数并返回其返回的 Promise
    • 第二个 .then 回调用于处理 getUserInfo 成功返回的用户信息并打印。
    • 使用 .catch 方法捕获整个过程中可能出现的错误并打印错误信息。

这种方式通过 Promise.then 链式调用,将第二个 Promise 的调用放在第一个 Promise 成功后的回调里,实现了两个异步操作的顺序执行。不过这种方式在处理多个嵌套的 Promise 时,代码会变得难以阅读和维护,也就是所谓的"回调地狱"问题。而使用 async/await 语法可以让代码更加简洁易读。

相关推荐
绝无仅有33 分钟前
使用 Docker 安装 Elastic Stack 并重置本地密码
后端·面试·github
老A技术联盟1 小时前
聊一聊消息中间件的后起之秀-pulsar及其实践
后端
隐-梵1 小时前
Android studio前沿开发--利用socket服务器连接AI实现前后端交互(全站首发思路)
android·服务器·人工智能·后端·websocket·android studio·交互
uhakadotcom1 小时前
Langflow:零基础快速上手AI流程可视化开发工具详解与实战案例
后端·面试·github
bobz9651 小时前
strongswan ipsec 端口使用
后端
陈哥聊测试1 小时前
这款自研底层框架,你说不定已经用上了
前端·后端·开源
一只叫煤球的猫1 小时前
分布式-跨服务事务一致性的常见解决方案
java·分布式·后端
扣丁梦想家1 小时前
Spring Boot 实现 Excel 导出功能(支持前端下载 + 文件流)
spring boot·后端·excel
调试人生的显微镜1 小时前
flutter ios 自定义ios插件
后端
仰望星空的打工人2 小时前
windows11家庭版安装docker
后端