乱用try...catch引发的故障报警

134 阅读4分钟

1. try...catch...捕获异常逻辑

  1. 多层try...catch...,错误会被距离最近的catch捕获
try {
  try {
    throw new Error("oops");
  }
  catch (ex) {
    console.error("inner", ex.message);
  }
  finally {
    console.log("finally");
  }
}
catch (ex) {
  console.error("outer", ex.message);
}

// Output:
// "inner" "oops"
// "finally"
  1. 在内层catch中再次抛出错误,会被外层捕获
try {
  try {
    throw new Error("oops");
  }
  catch (ex) {
    console.error("inner", ex.message);
    throw ex;
  }
  finally {
    console.log("finally");
  }
}
catch (ex) {
  console.error("outer", ex.message);
}

// Output:
// "inner" "oops"
// "finally"
// "outer" "oops"
  1. 从 finally 语句块返回
try {
  try {
    throw new Error("oops");
  }
  catch (ex) {
    console.error("inner", ex.message);
    throw ex;
  }
  finally {
    console.log("finally");
    return;
  }
}
catch (ex) {
  console.error("outer", ex.message);
}

// Output:
// "inner" "oops"
// "finally"

因为 finally 块里的 return 语句,"oops" 没有抛出到外层,从 catch 块返回的值同样适用

2. 异步下的错误拦截问题

监听Promise错误透出: unhandledrejection

1. 请求函数不做catch处理

const func1 = () => {
    return new Promise((resolve, reject)=> {
        setTimeout(() => {
            reject('失败')
        }, 1000)
    })
}

const func2 = async () => {
    try {
        const a = await func1();
        console.log('a', a);
    } catch (e) {
        console.log('func2 catch', e);
    }
}

func2();

// func2 catch 失败

2. 请求函数做catch处理

const func1 = () => {
    return new Promise((resolve, reject)=> {
        setTimeout(() => {
            reject('失败')
        }, 1000)
    }).catch((e) => {
        console.log('func1 catch', e)
    })
}

const func2 = async () => {
    try {
        const a = await func1();
        console.log('a', a);
    } catch (e) {
        console.log('func2 catch', e);
    }
}

func2();

// func1 catch 失败

3. 在catch中返回值

  1. 返回reject
const func1 = () => {
    return new Promise((resolve, reject)=> {
        setTimeout(() => {
            const error = new Error('fail');
            reject(error);
        }, 1000)
    }).then((data) => {
        console.log('func1 then', data);
        // 必须return
        return Promise.resolve(data);
    })
    .catch((e) => {
        console.log('func1 catch', e)
        // 如果是resolve,则走到正常逻辑
        return Promise.reject('func1:fail')
    })
}

const func2 = async () => {
    try {
        const a = await func1();
        console.log('a', a);
    } catch (e) {
        console.log('func2 catch', e);
    }
}

func2()

// func1 catch Error: fail
// func2 catch func1:fail

等同于

const func1 = () => {
    return new Promise((resolve, reject)=> {
        setTimeout(() => {
            const error = new Error('fail');
            reject(error);
        }, 1000)
    })
}

const func2 = async () => {
    return new Promise((resolve, reject)=> {
        func1()
            .then((data) => {
                console.log('func1 then', data);
                resolve(data);
            })
            .catch((e) => {
                console.log('func1 catch', e)
                reject('func1:fail')
            })
    })
}

const func3 = async () => {
    try {
        const a = await func2();
        console.log('a', a);
    } catch (e) {
        console.log('func3 catch', e);
    }
}

func3();

// func1 catch Error: fail
// func3 catch func1:fail
  1. 返回resolve
const func1 = () => {
    return new Promise((resolve, reject)=> {
        setTimeout(() => {
            // const error = new Error('fail');
            // reject(error);
            resolve(1000);
        }, 1000)
    }).then((data) => {
        console.log('func1 then', data);
        return Promise.reject(data);
    })
    .catch((e) => {
        console.log('func1 catch', e)
        // 如果是resolve,则走到正常逻辑
        return Promise.resolve(2000);
        // return Promise.reject('func1:fail')
    })
}

const func2 = async () => {
    try {
        const a = await func1();
        console.log('a', a);
    } catch (e) {
        console.log('func2 catch', e);
    }
}

func2()

如果直接返回一个相当于return Promise.resolve(值)

  1. finally
const func1 = () => {
    return new Promise((resolve, reject)=> {
        setTimeout(() => {
            // const error = new Error('fail');
            // reject(error);
            resolve(1000);
        }, 1000)
    }).then((data) => {
        console.log('func1 then', data);
        return Promise.reject(data);
    })
    .catch((e) => {
        console.log('func1 catch', e)
        // 如果是resolve,则走到正常逻辑
        // return Promise.resolve(2000);
        return Promise.reject('func1:fail')
    })
    .finally(() => {
        console.log('finally');
        return Promise.resolve(3000);
    })
}

const func2 = async () => {
    try {
        const a = await func1();
        console.log('a', a);
    } catch (e) {
        console.log('func2 catch', e);
    }
}

// func1 then 1000
// func1 catch 1000
// finally
// func2 catch func1:fail

finally里为reject时,finally返回值优先级最高,否则为catch。这块还没搞懂???

4. 无效的try...catch...

1. 没有运行的函数

const func1 = () => {
    return new Promise((resolve, reject)=> {
        setTimeout(() => {
            const error = new Error('fail');
            reject(error);
        }, 1000)
    })
}

const func2 = async () => {
    try {
        return new Promise((resolve, reject)=> {
            func1()
                .then((data) => {
                    console.log('func1 then', data);
                    resolve(data);
                })
                .catch((e) => {
                    console.log('func1 catch', e)
                    reject('func1:fail')
                })
        })
    } catch (e) {
        console.log('func2 catch', e);
    }
}

const func3 = async () => {
    try {
        const a = await func2();
        console.log('a', a);
    } catch (e) {
        console.log('func3 catch', e);
    }
}
func3();

// func1 catch Error: fail
// func3 catch func1:fail
const func1 = () => {
    try {
        return function a() {
            const a = 1;
            console.log('a', a.b.c);
        }
    } catch (e) {
        console.log('func1 catch', e);
    }
}

const func2 =() => {
    try {
        func1()();
    } catch (e) {
        console.log('func2 catch', e);
    }
}
func2();

// func2 catch TypeError
const func1 = () => {

        return function a() {
            try {
                const a = 1;
                console.log('a', a.b.c);
            } catch (e) {
                console.log('func1 catch', e);
            }
        }
}

const func2 =() => {
    try {
        func1()();
    } catch (e) {
        console.log('func2 catch', e);
    }
}

func2();

// func1 catch TypeError

2. 重复包裹

const func2 = async () => {
    try {
        const a = await new Promise((resolve, reject)=> {
            func1()
                .then((data) => {
                    console.log('func1 then', data);
                    resolve(data);
                })
                .catch((e) => {
                    console.log('func1 catch', e)
                    // reject('func1:fail')
                })
        })
        console.log('a', a);
    } catch (e) {
        console.log('func2 catch', e);
    }
}

// func1 catch Error: fail

3. 避免太多try...catch...

1. 直接catch

  1. 不会中断逻辑
  2. 错误不会透出
function func1 () {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('请求异常')
        }, 1000)
    })
}

async function func2 () {
    let data = await func1().catch(e => console.warn(e))
    // 执行没有中断,userInfo 为 undefined
    if (!data) return // 需要做非空校验
    console.log('data', data);
}

2. reject中断执行

  1. 会中断逻辑
  2. 错误会透出
function func1 () {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('请求异常')
        }, 1000)
    })
}

async function func2 () {
    let data = await func1().catch(e => {
        console.warn(e)
        return Promise.reject(e)
    })
  
    // 执行被中断,userInfo 为 undefined
    console.log('data', data);
}

3. await-to-js

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

函数to接受参数PromiseerrorExt,如果这个 Promise 成功时返回[null, data],如果异常时会判断是否带有errorExt参数(代表传递给 err 对象的附加信息),如果有时会与 catch 捕获的 err 合并返回,如果没有时返回[err, undefined]

4. babel插件

juejin.cn/post/715543…