JavaScript的异常处置

访客4年前关于黑客接单718

当 JavaScript 引擎执行 JavaScript 代码时,有可能会发生种种异常,例如是语法异常,语言中缺少的功效,由于来自服务器或用户的异常输出而导致的异常。

而 Javascript 引擎是单线程的,因此一旦遇到异常,Javascript 引擎通常会住手执行,壅闭后续代码并抛出一个异常信息,因此对于可预见的异常,我们应该捕捉并准确展示给用户或开发者。


Error工具

throw 和 Promise.reject() 可以抛出字符串类型的异常,而且可以抛出一个 Error 工具类型的异常。

一个 Error 工具类型的异常不仅包罗一个异常信息,同时也包罗一个追溯栈这样你就可以很容易通过追溯栈找到代码失足的行数了。

以是推荐抛出 Error 工具类型的异常,而不是字符串类型的异常。

建立自己的异常组织函数

function MyError(message) {
    var instance = new Error(message);
    instance.name = 'MyError';
    Object.setPrototypeOf(instance, Object.getPrototypeOf(this));
    return instance;
}

MyError.prototype = Object.create(Error.prototype, {
    constructor: {
        value: MyError,
        enumerable: false,
        writable: true,
        configurable: true
    }
});

if (Object.setPrototypeOf) {
    Object.setPrototypeOf(MyError, Error);
} else {
    MyError.__proto__ = Error;
}

export default MyError;

在代码中抛出自界说的异常类型并捕捉

try {
    throw new MyError("some message");
} catch(e){
    console.log(e.name + ":" + e.message);
}

Throw

throw expression;

throw 语句用来抛出一个用户自界说的异常。当前函数的执行将被住手(throw 之后的语句将不会执行),而且控制将被通报到挪用客栈中的之一个 catch 块。若是挪用者函数中没有 catch 块,程序将会终止。

try {
    console.log('before throw error');
    throw new Error('throw error');
    console.log('after throw error');
} catch (err) {
    console.log(err.message);
}

// before throw error
// throw error

Try / Catch

try {
   try_statements
}
[catch (exception) {
   catch_statements
}]
[finally {
   finally_statements
}]

try/catch 主要用于捕捉异常。try/catch 语句包罗了一个 try 块, 和至少有一个 catch 块或者一个 finally 块,下面是三种形式的 try 声明:

  • try...catch
  • try...finally
  • try...catch...finally

try 块中放入可能会发生异常的语句或函数

catch 块中包罗要执行的语句,当 try 块中抛出异常时,catch 块会捕捉到这个异常信息,并执行 catch 块中的代码,若是在 try 块中没有异常抛出,这 catch 块将会跳过。

finally 块在 try 块和 catch 块之后执行。无论是否有异常抛出或着是否被捕捉它总是执行。当在 finally 块中抛出异常信息时会覆盖掉 try 块中的异常信息。

try {
    try {
        throw new Error('can not find it1');
    } finally {
        throw new Error('can not find it2');
    }
} catch (err) {
    console.log(err.message);
}

// can not find it2

若是从 finally 块中返回一个值,那么这个值将会成为整个 try-catch-finally 的返回值,无论是否有 return 语句在 try 和 catch 中。这包罗在 catch 块里抛出的异常。

function test() {
    try {
        throw new Error('can not find it1');
        return 1;
    } catch (err) {
        throw new Error('can not find it2');
        return 2;
    } finally {
        return 3;
    }
}

console.log(test()); // 3

Try / Catch 性能

有一个人人众所周知的反优化模式就是使用 try/catch

在V8(其他 *** 引擎也可能泛起相同情形)函数中使用了 try/catch 语句不能够被V8编译器优化。参考http://www.html5rocks.com/en/tutorials/speed/v8/

window.onerror

通过在 window.onerror 上界说一个事宜监听函数,程序中其他代码发生的未被捕捉的异常往往就会被 window.onerror 上面注册的监听函数捕捉到。而且同时捕捉到一些关于异常的信息。

window.onerror = function (message, source, lineno, colno, error) { }
  • message:异常信息(字符串)
  • source:发生异常的剧本URL(字符串)
  • lineno:发生异常的行号(数字)
  • colno:发生异常的列号(数字)
  • error:Error工具(工具)

注重:Safari 和 IE10 还不支持在 window.onerror 的回调函数中使用第五个参数,也就是一个 Error 工具并带有一个追溯栈

try/catch 不能够捕捉异步代码中的异常,然则其将会把异常抛向全局然后 window.onerror 可以将其捕捉。

try {
    setTimeout(() => {
        throw new Error("some message");
    }, 0);
} catch (err) {
    console.log(err);
}
// Uncaught Error: some message
window.onerror = (msg, url, line, col, err) => {
    console.log(err);
}
setTimeout(() => {
    throw new Error("some message");
}, 0);
// Error: some message

在Chrome中,window.onerror 能够检测到从其余域引用的script文件中的异常,而且将这些异常符号为Script error。若是你不想处置这些从其余域引入的script文件,那么可以在程序中通过Script error符号将其过滤掉。然而,在Firefox、Safari或者IE11中,并不会引入跨域的 *** 异常,纵然在Chrome中,若是使用 try/catch 将这些憎恶的代码笼罩,那么Chrome也不会再检测到这些跨域异常。

在Chrome中,若是你想通过 window.onerror 来获取到完整的跨域异常信息,那么这些跨域资源必须提供合适的跨域头信息。


Promise中的异常

Promise中抛出异常

new Promise((resolve,reject)=>{
    reject();
})
Promise.resolve().then((resolve,reject)=>{
    reject();
});
Promise.reject();
throw expression;

Promise中捕捉异常

promiseObj.then(undefined, (err)=>{
    catch_statements
});
promiseObj.catch((exception)=>{
    catch_statements
})

在 JavaScript 函数中,只有 return / yield / throw 会中止函数的执行,其他的都无法阻止其运行到竣事的。

在 resolve / reject 之前加上 return 能阻止往下继续运行。

without return:

Promise.resolve()
.then(() => {
    console.log('before excute reject');
    reject(new Error('throw error'));
    console.log('after excute reject');
})
.catch((err) => {
    console.log(err.message);
});

// before excute reject
// throw error
// after excute reject

use return:

Promise.resolve()
.then(() => {
    console.log('before excute reject');
    return reject(new Error('throw error'));
    console.log('after excute reject');
})
.catch((err) => {
    console.log(err.message);
});

// before excute reject
// throw error

Throw or Reject

无论是 try/catch 照样 promise 都能捕捉到的是“同步”异常

reject 是回调,而 throw 只是一个同步的语句,若是在另一个异步的上下文中抛出,在当前上下文中是无法捕捉到的。

因此在 Promise 中使用 reject 抛出异常。否则 catch 有可能会捕捉不到。

Promise.resolve()
.then(() => {
    setTimeout(()=>{
        throw new Error('throw error');
    },0);
})
.catch((err) => {
    console.log(err);
});

// Uncaught Error: throw error
Promise.resolve()
.then(() => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject(new Error('throw error'));
        }, 0);
    });
})
.catch((err) => {
    console.log(err);
});

// Error: throw error

window.onunhandledrejection

window.onunhandledrejection 与 window.onerror 类似,在一个JavaScript Promise 被 reject 然则没有 catch 来捕捉这个 reject时触发。而且同时捕捉到一些关于异常的信息。

window.onunhandledrejection = event => { 
    console.log(event.reason);
}

event事宜是 PromiseRejectionEvent 的实例,它有两个属性:

  • event.promise:被 rejected 的 JavaScript Promise
  • event.reason:一个值或 Object 解释为什么 promise 被 rejected,是 Promise.reject() 中的内容。

window.rejectionhandled

由于 Promise 可以延后挪用 catch 方式,若在抛出 reject 时未挪用 catch 举行捕捉,但稍后再次挪用 catch,此时会触发 rejectionhandled 事宜。

window.onrejectionhandled = event =>
{
    console.log('rejection handled');
}

let p = Promise.reject(new Error('throw error'));

setTimeout(()=>{
    p.catch(e=>{console.log(e)});
},1000);

// Uncaught (in promise) Error: throw error
// 1秒后输出
// Error: throw error
// rejection handled


统一异常处置

代码中抛出的异常,一种是要展示给用户,一种是展示给开发者。

对于展示给用户的异常,一样平常使用 alert 或 toast 展示;对于展示给开发者的异常,一样平常输出到控制台。

在一个函数或一个代码块中可以把抛出的异常统一捕捉起来,根据差别的异常类型以差别的方式展示,对于。

需要点击确认的异常类型:
ensureError.js

function EnsureError(message = 'Default Message') {
    this.name = 'EnsureError';
    this.message = message;
    this.stack = (new Error()).stack;
}
EnsureError.prototype = Object.create(Error.prototype);
EnsureError.prototype.constructor = EnsureError;

export default EnsureError;

弹窗提醒的异常类型:
toastError.js

function ToastError(message = 'Default Message') {
    this.name = 'ToastError';
    this.message = message;
    this.stack = (new Error()).stack;
}
ToastError.prototype = Object.create(Error.prototype);
ToastError.prototype.constructor = ToastError;

export default ToastError;

提醒开发者的异常类型:
devError.js

function DevError(message = 'Default Message') {
    this.name = 'ToastError';
    this.message = message;
    this.stack = (new Error()).stack;
}
DevError.prototype = Object.create(Error.prototype);
DevError.prototype.constructor = DevError;

export default DevError;

异常处置器:
抛出通俗异常时,可以带上 stackoverflow 上问题的列表,利便开发者查找缘故原由。
errorHandler.js

相关文章

训狗的基础原理是什么(训犬的基本原理分析)

训狗的基础原理是什么(训犬的基本原理分析)

看着家里的毛孩子逐渐适应了环境,家长们也开始摩拳擦掌想要训练狗狗一些炫酷的技能了,不过诸君且慢! 穷理尽性,方能事半功倍。在开始训犬之前,我们不妨来了解一下训犬的基本原理。   在19世纪的...

押一付三什么意思?押一付三必须租3个月吗

押一付三什么意思?押一付三必须租3个月吗

租房子的时候,会有不同的付款方式,押一付三是什么意思呢?接下来,PChouse就为大家细细道来。 押一付三:押一是指,先交一个月的押金,付三是指,最少三个月的房租;房租是1000/月,押一付三给...

定位微信地址不被对方发现(黑客技术定位地址)?

黑客技术定位地址,定位微信地址对于一个技术成熟的黑客可以说是轻而易举的工作,那么究竟是怎么操作来定位别人的微信地址而不被对方所发现的呢,下面这种简单办法可以告诉你答案。 定位微信地址不被对方发现...

查看我老婆QQ已删聊天记录

. 当孩子会走路的时候走路不稳很正常,但是当孩子两岁了还是不稳的话是不是不正常呢,尤其是一些孩子在走路的时候喜欢踮起脚尖,有的家长一卡式没发现,觉得孩子是闹得玩的,其实这是肌肉发育的问题。下面友谊长...

有名的白帽子黑客(中国最年轻的白帽子黑客)

有名的白帽子黑客(中国最年轻的白帽子黑客)

本文导读目录: 1、年仅10岁的天才“黑客”:因不想写作业而黑掉学校网站,他现状如何呢? 2、中国有哪些有名的黑客? 3、15年前,那个黑掉阿里内网的“黑客男孩”吴翰清,如今情况怎样? 4...

鱼乐汇和黑客罗鲤二号搭配咋样的简单介绍

鱼乐汇和黑客罗鲤二号搭配咋样的简单介绍

螺鲤2号怎么搭配老三样 1、夏天老三样士野战蓝鲫、918野战、速攻2按照1:1:0.5的比例配成饵料,再和水按照1:1的比例混合均匀即可使用。这样搭配的饵料使用率比较高。在野战蓝鲫用量较小时,开出的饵...