ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScriptの例外処理の説明

JavaScriptの例外処理の説明

一个新手
一个新手オリジナル
2017-10-25 14:49:331471ブラウズ

JavaScript エンジンが JavaScript コードを実行すると、構文の例外、言語の機能の欠落、サーバーまたはユーザーからの異常な出力による例外など、さまざまな例外が発生する可能性があります。

そして、

Javascriptエンジンはシングルスレッドであるため、例外が発生すると、Javascriptエンジンは通常実行を停止し、後続のコードをブロックし、例外メッセージをスローします。そのため、予見可能な例外については、それらをキャッチして正しく表示する必要がありますユーザーや開発者に。

Error object

throwPromise.reject() は、文字列型の例外をスローすることができ、また Error オブジェクト型の例外をスローすることができます。

A

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 ブロックと、少なくとも 1 つの catch ブロックまたは finally ブロックが含まれます。 try ステートメントの 3 つの形式は、次のとおりです。

  • try...catch

  • try...finally

  • try...catch...finally

try 例外を生成する可能性のあるステートメントまたは関数はブロック内に配置されます

catch ブロックには以下が含まれます実行されるステートメント。 try ブロックで例外がスローされた場合、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ブロックから返された場合、tryreturnステートメントがあるかどうかに関係なく、この値はtry-catch-finally全体の戻り値になります。キャッチ。これには、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 ステートメント (同じ状況が他の JS エンジンでも発生する可能性があります) 関数は、V8 コンパイラーでは最適化できません。 http://www.html5rocks.com/en/tutorials/speed/v8/

window.onerror

を参照

window.onerrorでイベントリスニング関数を定義することで、プログラム内の他のコードによって生成されたキャッチされないエラーが発生します。多くの場合、上記で登録された listen 関数 window.onerror によってキャッチされます。同時に、例外に関する情報を取得します。

window.onerror = function (message, source, lineno, colno, error) { }

  • message: 例外情報 (文字列)

    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 errorsource: 例外が発生したスクリプト URL (文字列)

🎜🎜🎜lineno : 例外が発生した行番号(number)🎜🎜🎜🎜<code>colno: 例外が発生した列番号(number)🎜🎜🎜🎜error:エラー オブジェクト (オブジェクト)🎜🎜🎜🎜注: Safari と IE10 は、🎜window.onerror🎜 のコールバック関数の 5 番目のパラメーターの使用をまだサポートしていません。これは、トレースバック スタックを持つ 🎜Error🎜 オブジェクトです🎜🎜🎜try /catch🎜 非同期コード内の例外はキャッチできませんが、例外はグローバルにスローされ、🎜window.onerror🎜 はそれをキャッチできます。 🎜
new Promise((resolve,reject)=>{
    reject();
})
Promise.resolve().then((resolve,reject)=>{
    reject();
});
🎜 Chrome では、🎜window.onerror🎜 が他のドメインから参照されるスクリプト ファイルの例外を検出し、これらの例外を スクリプト エラー としてマークできます。他のドメインからインポートされたこれらのスクリプト ファイルを処理したくない場合は、プログラム内の Script error タグを使用してそれらのスクリプト ファイルをフィルタリングして除外できます。ただし、Firefox、Safari、IE11 ではクロスドメイン JS 例外が導入されていません。これらの厄介なコードを 🎜try/catch🎜 で囲むと、Chrome はこれらの異常なクロスドメイン JS 例外を検出しなくなります。 🎜

在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(&#39;before excute reject&#39;);
    reject(new Error(&#39;throw error&#39;));
    console.log(&#39;after excute reject&#39;);
})
.catch((err) => {
    console.log(err.message);
});

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

use return

Promise.resolve()
.then(() => {
    console.log(&#39;before excute reject&#39;);
    return reject(new Error(&#39;throw error&#39;));
    console.log(&#39;after excute reject&#39;);
})
.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(&#39;throw error&#39;);
    },0);
})
.catch((err) => {
    console.log(err);
});

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

// Error: throw error

window.onunhandledrejection

window.onunhandledrejectionwindow.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(&#39;rejection handled&#39;);
}

let p = Promise.reject(new Error(&#39;throw error&#39;));

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

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

统一异常处理

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

对于展示给用户的异常,一般使用 alerttoast 展示;对于展示给开发者的异常,一般输出到控制台。

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

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

function EnsureError(message = &#39;Default Message&#39;) {
    this.name = &#39;EnsureError&#39;;
    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 = &#39;Default Message&#39;) {
    this.name = &#39;ToastError&#39;;
    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 = &#39;Default Message&#39;) {
    this.name = &#39;ToastError&#39;;
    this.message = message;
    this.stack = (new Error()).stack;
}
DevError.prototype = Object.create(Error.prototype);
DevError.prototype.constructor = DevError;

export default DevError;

异常处理器:
抛出普通异常时,可以带上 stackoverflow 上问题的列表,方便开发者查找原因。
errorHandler.js

import EnsureError from &#39;./ensureError.js&#39;;
import ToastError from &#39;./toastError.js&#39;;
import DevError from &#39;./devError.js&#39;;
import EnsurePopup from &#39;./ensurePopup.js&#39;;
import ToastPopup from &#39;./toastPopup.js&#39;;

function errorHandler(err) {
    if (err instanceof EnsureError) {
        EnsurePopup(err.message);
    } else if (err instanceof ToastError) {
        ToastPopup(err.message);
    }else if( err instanceof DevError){
        DevError(err.message);
    }else{
        error.message += ` https://stackoverflow.com/questions?q=${encodeURI(error.message)}`
        console.error(err.message);    
    }
}

window.onerror = (msg, url, line, col, err) => {
    errorHandler(err);
}

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

export default errorHandler;


以上がJavaScriptの例外処理の説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。