一般情况下,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 分钟前
添加购物车-02.代码开发
java·服务器·前端·后端·spring·微信小程序·苍穹外卖
幽络源小助理2 小时前
懒人美食帮SpringBoot订餐系统开发实现
java·spring boot·后端·美食
源码云商4 小时前
基于Spring Boot + Vue的母婴商城系统( 前后端分离)
java·spring boot·后端
还听珊瑚海吗8 小时前
基于SpringBoot的抽奖系统测试报告
java·spring boot·后端
你怎么知道我是队长10 小时前
Go语言标识符
后端·golang
sco528214 小时前
SpringBoot 自动装配原理 & 自定义一个 starter
java·spring boot·后端
海风极客15 小时前
《Go小技巧&易错点100例》第三十三篇
开发语言·后端·golang
养军博客15 小时前
Spring boot 简单开发接口
java·spring boot·后端
计算机学姐17 小时前
基于SpringBoot的在线教育管理系统
java·vue.js·spring boot·后端·mysql·spring·mybatis
有梦想的攻城狮18 小时前
spring中的@Value注解详解
java·后端·spring·value注解