如何优雅的捕获 await 的错误
一. 前言
场景: 调用a接口获取到返回的成功数据resulta 使用resulta才能去调用b接口 调用b接口获取到返回的成功数据resultb 使用resultb去调用c接口
二. 不使用await-to-js库
function funLogin() {
return new Promise((resolve, reject) => {
console.log('调用成功-登录成功');
// resolve(`1:`)
reject('error-test')
})
}
function funUserId(params) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('调用成功-返回人员id');
resolve(`2:${params}`)
}, 1000);
})
}
function funUserInfo(params) {
return new Promise((resolve, reject) => {
console.log('调用成功-返回人员的信息');
resolve(`3:${params}`)
})
}
不使用await-to-js
async function test() {
let resultLogin, resultUserId, result
try {
resultLogin = await funLogin()
console.log(resultLogin);
} catch (error) {
console.log('funLogin error:',error);
}
if (resultLogin) {
try {
resultUserId = await funUserId(resultLogin)
// console.log(resultUserId);
} catch (error) {
console.log(error);
}
if (resultUserId) {
try {
result = await funUserInfo(resultUserId)
// console.log(result);
} catch (error) {
console.log(error);
}
}
}
}
test()
三. 为啥要出现这个库呢
我觉得是为了让代码更加优雅 下面是我对官方文档的解读
四. 进入源码
默认给的是ts版本
/**
* @param { Promise } promise
* @param { Object= } errorExt - Additional Information you can pass to the err object
* @return { Promise }
*/
export function to<T, U = Error> (
promise: Promise<T>,
errorExt?: object
): Promise<[U, undefined] | [null, T]> {
return promise
.then<[null, T]>((data: T) => [null, data])
.catch<[U, undefined]>((err: U) => {
if (errorExt) {
const parsedError = Object.assign({}, err, errorExt);
return [parsedError, undefined];
}
return [err, undefined];
});
}
export default to;
打包以后可以查看它的js版本
function to(promise, errExt) {
return promise.then(res => {
return [null,res]
}).catch(err => {
if (errExt) {
const errObj = Object.assign({},err,errExt)
return [errObj, undefined]
}else {
return [err, undefined]
}
})
}
源码解析 传入一个包含reject或者resolve状态的promise或者说errExt(额外的错误信息) 如果promise状态为成功,那么返回一个数组,数组的第一个元素为null、数组的第二个元素为res 如果promise状态为失败,那么先判断是否传入了errExt 如果传入了errExt 那么将err与errExt整合成errObj,然后返回一个数组,数组的第一个元素为errObj、数组的第二个元素为undefined 如果没有传入errExt,那么直接返回一个数组,数组的第一个元素为err、数组的第二个元素为undefined
使用await-to-js 在浏览器中测试
async function test() {
const [err1,resultLogin] = await to(funLogin())
if (err1) {throw new Error(err1)}
const [err2,resultUserId] = await to(funUserId(resultLogin))
if (err2) {throw new Error(err2)}
const [err3,res] = await to(funUserId(resultUserId))
if (err3) {throw new Error(err3)}
}
test()
//调用成功-登录成功
// 1.html:115 Uncaught (in promise) Error: error-test
// at test (1.html:115:20)
代码精简了很多
跑一跑官方测试用例 这里是测试ts版本的
import { to } from "../src/await-to-js";
describe("Await to test", async () => {
// 测试 成功返回结果 return <null,number>
it("should return a value when resolved", async () => {
const testInput = 41;
const promise = Promise.resolve(testInput);
const [err, data] = await to<number>(promise);
expect(err).toBeNull();
expect(data).toEqual(testInput);
});
it("should return an error when promise is rejected", async () => {
// 测试 失败处理结果 return <Error,undefined>
const testInput = 41;
const promise = Promise.reject("Error");
const [err, data] = await to<number>(promise);
expect(err).toEqual("Error");
expect(data).toBeUndefined();
});
it("should add external properties to the error object", async () => {
// 测试 失败处理结果 return 自定义类型的error
const promise = Promise.reject({ error: "Error message" });
const [err] = await to<string, { error: string; extraKey: number }>(promise, {
extraKey: 1,
});
expect(err).toBeTruthy(); // err是否为ture 这里对于单元测试 toBe(xx) 、totoBeTruthy()、toBeTrue()这三者的区别联系 楼主就没有深究了
expect((err as any).extraKey).toEqual(1); // err的extraKey是否为1
expect((err as any).error).toEqual("Error message"); // err的extraKey是否为"Error message"
});
it("should receive the type of the parent if no type was passed", async () => {
// 没有设置类型声明时,会去自动推导
let user: { name: string };
let err: Error;
[err, user] = await to(Promise.resolve({ name: "123" }));
expect(user.name).toEqual("123");
});
});