Promise基础(消化错误和抛出错误)

本文详细解析了JavaScript中Promise对象的工作原理,包括then、catch、finally等方法的使用方式及内部实现机制,帮助读者深入理解异步编程。

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

then

then 函数的会接收两个回调函数,一个是 onFulfilled 函数,一个是 onRejected 函数

如果这两个回调函数没有写返回值,默认会 return undefined;

进入下一个函数的 onFulfilled 函数中

const p = new Promise((resolve, reject) => {
  resolve(22);
});
p.then(
  (success1) => {
    console.log("success1", success1); // "success2" 22
    // 没写 return 默认返回 return undefined
  },
  (err1) => {
    console.log("err1", err1);
  }
).then(
  (success2) => {
    console.log("success2", success2); // "success2" undefined
  },
  (err2) => {
    console.log("err2", err2);
  }
);

在这两个回调中 return xxx ,相当于调用 return new Promise((resolve) => resolve(xxx));

const p = new Promise((resolve, reject) => {
  resolve(22);
});
p.then(
  (success1) => {
    return new Promise((resolve, reject) => resolve("success"));
    // 等价于
    return "success";
  },
  (err1) => {
    console.log("err1", err1);
  }
).then(
  (success2) => {
    console.log("success2", success2); // "success2" "success"
  },
  (err2) => {
    console.log("err2", err2);
  }
);

onFulfilled 函数和 onRejected 函数中默认返回的都是成功,如果需要返回失败需要显示调用 reject 或者用 throw 抛出错误可以

const p = new Promise((resolve, reject) => {
  resolve(22);
});
p.then(
  (success1) => {
    return new Promise((resolve, reject) => reject("error"));
    // 等价于
    // throw "error";
  },
  (err1) => {
    console.log("err1", err1);
  }
).then(
  (success2) => {
    console.log("success2", success2);
  },
  (err2) => {
    console.log("err2", err2); // "err2" error
  }
);

总结:在 then 回调中 return xxx 会被自动包装成 return new Promise((resolve) => resolve(xxx));

catch

catch 是用来处理 rejected 状态,是 then 函数的一种特例,相当于 then(null, (err) => {});

catch 为什么能捕获前面的错误?

onRejected 函数中,如果没有显示抛出错误,默认会 return undefined; 进入一下个 onFulfilled 函数

finally

finally 不管当前 promise 是什么状态都会执行,也是 then 函数的一种特例,相当于 `then(result => result, err => new Promsie((_, reject) => reject(err)));

Promise.resolve

Promise.resolvePromisefulfilled 状态时的简写,相当于 new Promise(resolve => resolve(xxx))

onFulfilled 函数接收参数

  • 当参数是普通参数时,会直接传递给后面 then 函数
    new Promise((resolve) => resolve({ name: "uccs" })).then((data) => {
      console.log(data);
    });
    
  • 当参数是 Promise 对象时,后面的 then 会根据传递的 Promise 对象的状态变化执行哪一个回调
    const p = new Promise((resolve, reject) => {
      setTimeout(resolve, 1000, "我执行了");
    });
    new Promise((resolve) => resolve(p)).then((data) => {
      console.log(data);
    });
    
  • 具有 then 方法的对象
    • 用这种这种方式,如果需要改变 Promise 状态是,不能使用 return 形式,这个 then 方法也是有两个回调函数的:onFulfilledonRejected
    const thenable = {
      then(resolve, reject) {
        console.log("thenable");
      },
    };
    new Promise((resolve) => resolve(thenable)).then((data) => {
      console.log(data);
    });
    

Promise.reject

Promise.rejectPromiserejected 状态是的简写,相当于 new Promise((_, reject) => reject(xxx))

onRejected 函数不管接收什么参数,都会原封不动的向后传递,作为后续方法的参数

### 关于 TypeScript 报错 `Property 'data' does not exist on type 'void'` 在 TypeScript 中,`Property 'data' does not exist on type 'void'` 这类错误通常是因为尝试访问一个返回值为 `void` 的函数的结果属性。由于 `void` 类型表示没有任何值,因此无法在其上定义或访问任何属性。 以下是可能的原因以及解决方案: #### 可能原因分析 1. **函数未正确返回数据** 如果某个函数被声明为返回 `void` 类型,则该函数不会返回任何有意义的数据。然而,开发者可能会试图从这样的函数中读取某些属性(例如 `data`),这就会引发上述错误[^1]。 2. **类型推断不匹配** 当调用方法时,如果没有明确指定其返回类型或者实际返回的内容与预期不符,也可能触发此问题。比如,假设某 API 调用应该返回带有 `data` 字段的对象,但如果它实际上返回的是 `undefined` 或者其他不符合期望的形式,也会造成类似的错误消息[^2]。 3. **RxJS 流处理不当** 在使用 RxJS 库进行异步操作时,如果订阅了一个 Observable 并期待其中包含特定结构的数据却忘记导入必要的操作符(如 `.pipe()` 相关映射功能),那么最终接收到的可能是经过修改后的流形式——即不再具备原始接口定义下的成员变量【如 data】从而抛出异常提示找不到对应字段名的情况存在可能性较大一些[^5]. --- #### 解决方案 ##### 方法一:调整函数签名以反映真实行为 确保所有涉及逻辑链路里的每一步骤都清晰表达出来它们各自的职责所在;对于那些确实会产生有效输出结果的操作而言,则需将其设置成恰当非空泛型参数而非简单粗暴地标记成Void即可解决问题根源之一部分情况适用于此处提到过的场景当中去实践应用起来效果更佳一点哦😊! 示例代码如下所示: ```typescript function fetchData(): { data: string } { return { data: "exampleData" }; } const result = fetchData(); console.log(result.data); // 正确运行无误 ``` ##### 方法二:利用可选链 (Optional Chaining) 假如不确定目标对象是否存在所需属性前先做一层保护措施再继续往下执行后续动作就不会轻易崩溃啦😎!通过引入ES2020新增特性optional chaining(`?.`)来简化原本繁琐冗长的传统判断写法让整体看起来更加简洁明了易懂哈😄! 例子演示如下这般模样👇🏻👇🏻👇🏻: ```typescript let possibleUndefinedValue: undefined | { data?: string }; if (possibleUndefinedValue?.data) { console.log('Data exists:', possibleUndefinedValue.data); } else { console.warn('No valid data found.'); } ``` ##### 方法三:强制类型转换 当确认当前上下文中使用的实体的确拥有我们所需要的特性时候可以通过as关键字来进行手动干预告诉编译器不必担心安全方面的问题因为它已经满足条件要求所以允许这样做的方式也是可行的一种手段呢😉! 举个栗子🌰来看一下具体实现过程吧🧐: ```typescript declare const someFunctionReturningUnknown: () => unknown; // 使用 as 断言改变类型解释 const assumedResult = someFunctionReturningUnknown() as { data: number[] }; assumedResult.data.forEach(item => console.log(item)); ``` ##### 方法四:改进 Promise/Axios 请求处理流程 针对网络请求这类常见场合经常会出现因为回调机制设计不合理而导致类似现象发生的现象特别多见于是乎这里给出几个改进建议供大家参考学习借鉴吸收消化运用到自己的项目实践中去💪! - 明确指出Promise resolve出来的payload到底是什么样子的东西; - 对axios实例加以配置使其默认解析response body而不是整个http response object本身作为成功状态下的resolve value内容传递给then handler function处理; 样例展示如下图所呈现那样👀: ```typescript import axios from 'axios'; interface ApiResponse<T> { success: boolean; message?: string; data?: T; } async function fetchApiData(url: string): Promise<ApiResponse<any>> { try { const resp = await axios.get(url); // 假设服务器端遵循统一响应格式 if (!resp.data.success || !resp.data.data) throw new Error(resp.data.message ?? 'Unexpected server reply'); return resp.data; } catch(err){ console.error("Failed to load api data:", err); throw err; } } fetchApiData('/api/example') .then((res) => res.data && console.log(res.data)) .catch(console.error); ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值