摘要:調(diào)用堆棧實(shí)際上就是一個(gè)方法列表,按調(diào)用順序保存所有在運(yùn)行期被調(diào)用的方法。調(diào)用堆棧會(huì)將當(dāng)前正在執(zhí)行的函數(shù)調(diào)用壓入堆棧,一旦函數(shù)調(diào)用結(jié)束,又會(huì)將它移出堆棧。
原文
JavaScript Errors and Stack Traces in Depth
調(diào)用棧Call Stack是如何工作的棧是一個(gè)后進(jìn)先出LIFO (Last in,F(xiàn)irst out)的數(shù)據(jù)結(jié)構(gòu)。調(diào)用堆棧實(shí)際上就是一個(gè)方法列表,按調(diào)用順序保存所有在運(yùn)行期被調(diào)用的方法。調(diào)用堆棧會(huì)將當(dāng)前正在執(zhí)行的函數(shù)調(diào)用壓入堆棧,一旦函數(shù)調(diào)用結(jié)束,又會(huì)將它移出堆棧。
用console.trace()編寫一個(gè)簡(jiǎn)單的例子來演示一下
function c() { console.log("c"); console.trace(); } function b() { console.log("b"); c(); } function a() { console.log("a"); b(); } a();
我們可以看到console輸出的結(jié)果
console.trace c @ VM59:3 b @ VM59:7 a @ VM59:11 (anonymous) @ VM59:13
我們調(diào)用console.trace()是在c方法里,這個(gè)時(shí)候c還在執(zhí)行,并沒有返回,因此從console就能看到調(diào)用堆棧頂就是c。我們可以稍微改變一下,比如把console.trace()放在b方法里調(diào)用,如下:
function c() { console.log("c"); } function b() { console.log("b"); c(); console.trace(); } function a() { console.log("a"); b(); } a();
這時(shí)候我們?cè)儆^察console,就看不到c方法了
VM61:8 console.trace b @ VM61:8 a @ VM61:13 (anonymous) @ VM61:16
因?yàn)?b>console.trace()的調(diào)用是發(fā)生在了c調(diào)用之后,因此這個(gè)時(shí)候,棧頂c的幀已經(jīng)出棧,自然就看不到了。
Error對(duì)象以及異常處理通常程序有異常的時(shí)候都會(huì)有一個(gè)Error對(duì)象拋出。Error.prototype有以下幾種標(biāo)準(zhǔn)屬性:
constructor
message
name
更多的,可以翻翻MDN的文檔。其中有一個(gè)stack屬性,要重點(diǎn)關(guān)注。盡管這是一個(gè)非標(biāo)準(zhǔn)屬性,但是絕大多數(shù)瀏覽器都支持這個(gè)屬性。
一般我們使用try/catch來捕獲異常,同時(shí),我們還可以使用finally來做一些清理的工作,因?yàn)?b>finally里的代碼是一定會(huì)執(zhí)行的。
try { console.log("The try block is running..."); } finally { try { throw new Error("Error inside finally."); } catch (err) { console.log("Caught an error inside the finally block."); } }
有一個(gè)值得探討的地方,那就是,你可以throw任何數(shù)據(jù)而不僅僅是一個(gè)Error類的實(shí)例。
function runWithoutThrowing(func) { try { func(); } catch (e) { console.log("There was an error, but I will not throw it."); console.log("The error"s message was: " + e.message) } } function funcThatThrowsString() { throw "I am a String."; } runWithoutThrowing(funcThatThrowsString);
這種情況下,e.message的值一定就是undefined了,因?yàn)槟銙伋龅牟⒉皇且粋€(gè)Error類的實(shí)例。
異常還可以作為第一個(gè)參數(shù)傳給callback函數(shù)。舉個(gè)fs.readdir的例子,
const fs = require("fs"); fs.readdir("/example/i-do-not-exist", function callback(err, dirs) { if (err instanceof Error) { // `readdir` will throw an error because that directory does not exist // We will now be able to use the error object passed by it in our callback function console.log("Error Message: " + err.message); console.log("See? We can use Errors without using try statements."); } else { console.log(dirs); } });處理調(diào)用堆棧
思路就兩種:
Error.captureStackTrace(NodeJS)
Error.prototype.stack
Error.captureStackTrace是NodeJS提供的一個(gè)方法,這個(gè)方法會(huì)捕捉當(dāng)前的調(diào)用堆棧,然后保存到你指定的對(duì)象。
const myObj = {}; function c() { } function b() { // Here we will store the current stack trace into myObj Error.captureStackTrace(myObj); c(); } function a() { b(); } // First we will call these functions a(); // Now let"s see what is the stack trace stored into myObj.stack console.log(myObj.stack);
另外一種就是利用Error對(duì)象的stack屬性。但里有個(gè)問題,就是你不知道在try/catch里拋出的是什么樣的值,這個(gè)值它不一定是Error類的實(shí)例。不過我們依然能夠處理,而且是非常巧妙的進(jìn)行處理。比如看看Chai這個(gè)斷言庫(kù)的AssertionError類的構(gòu)造函數(shù)。
// `ssfi` stands for "start stack function". It is the reference to the // starting point for removing irrelevant frames from the stack trace function AssertionError (message, _props, ssf) { var extend = exclude("name", "message", "stack", "constructor", "toJSON") , props = extend(_props || {}); // Default values this.message = message || "Unspecified AssertionError"; this.showDiff = false; // Copy from properties for (var key in props) { this[key] = props[key]; } // Here is what is relevant for us: // If a start stack function was provided we capture the current stack trace and pass // it to the `captureStackTrace` function so we can remove frames that come after it ssf = ssf || arguments.callee; if (ssf && Error.captureStackTrace) { Error.captureStackTrace(this, ssf); } else { // If no start stack function was provided we just use the original stack property try { throw new Error(); } catch(e) { this.stack = e.stack; } } }參考文檔
arguments.callee
arguments.caller
Error
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/89863.html
摘要:幸運(yùn)的是,使用符號(hào)創(chuàng)建的構(gòu)造器,如果在不使用來調(diào)用,則始終會(huì)報(bào)錯(cuò),即使在非嚴(yán)格模式下也不會(huì)產(chǎn)生問題。 來源:ApacheCN『JavaScript 編程精解 中文第三版』翻譯項(xiàng)目原文:Bugs and Errors 譯者:飛龍 協(xié)議:CC BY-NC-SA 4.0 自豪地采用谷歌翻譯 部分參考了《JavaScript 編程精解(第 2 版)》 調(diào)試的難度是開始編寫代碼的兩倍。 因此,如...
摘要:如果我們進(jìn)入一個(gè)函數(shù),我們?cè)诙褩5捻敳?。看看下面的代碼當(dāng)引擎開始執(zhí)行此代碼時(shí),調(diào)用堆棧將為空。之后,步驟如下調(diào)用堆棧中的每個(gè)條目稱為堆棧幀。這正是拋出異常時(shí)構(gòu)造堆棧跟蹤的方式當(dāng)異常發(fā)生時(shí),它基本上是調(diào)用堆棧的狀態(tài)。 隨著JavaScript越來越受歡迎,團(tuán)隊(duì)正在利用這個(gè)技術(shù)棧在多個(gè)層次- 前端,后端,混合應(yīng)用程序,嵌入式設(shè)備等等提供支持。 這篇文章旨在成為系列中第一個(gè)旨在深入挖掘Jav...
摘要:譯者注翻譯一個(gè)對(duì)新手比較友好的工作原理解析系列文章注意以下全部是概念經(jīng)驗(yàn)豐富的老鳥可以離場(chǎng)啦正文從這里開始隨著的流行團(tuán)隊(duì)們正在利用來支持多個(gè)級(jí)別的技術(shù)棧包括前端后端混合開發(fā)嵌入式設(shè)備以及更多這篇文章旨在成為深入挖掘和實(shí)際上他是怎么工作的系列 譯者注 翻譯一個(gè)對(duì)新手比較友好的 JavaScript 工作原理解析系列文章 注意: 以下全部是概念,經(jīng)驗(yàn)豐富的老鳥可以離場(chǎng)啦 正文從這里開始 隨...
摘要:每個(gè)函數(shù)調(diào)用都將開辟出一小塊稱為堆棧幀的內(nèi)存。當(dāng)?shù)诙€(gè)函數(shù)開始執(zhí)行,堆棧幀增加到個(gè)。當(dāng)這個(gè)函數(shù)調(diào)用結(jié)束后,它的幀會(huì)從堆棧中退出。保持堆棧幀跟蹤函數(shù)調(diào)用的狀態(tài),并將其分派給下一個(gè)遞歸調(diào)用迭。 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-《You-Dont-Know-JS》作者 關(guān)于譯者:這是一個(gè)流淌著滬江血液的純粹工程:認(rèn)真,是 HTM...
摘要:?jiǎn)卧獪y(cè)試會(huì)體現(xiàn)出以上錯(cuò)誤處理程序的作用如果出現(xiàn)問題,錯(cuò)誤處理程序就會(huì)返回。同時(shí)錯(cuò)誤會(huì)展開堆棧,這對(duì)調(diào)試非常有幫助。展開堆棧處理異常的一種方式是在調(diào)用堆棧的頂部加入。確保你的錯(cuò)誤處理處在相同域中,這樣會(huì)保留原始消息,堆棧和自定義錯(cuò)誤對(duì)象。 JavaScript的事件驅(qū)動(dòng)范式增添了豐富的語(yǔ)言,也是讓使用JavaScript編程變得更加多樣化。如果將瀏覽器設(shè)想為JavaScript的事件驅(qū)動(dòng)...
閱讀 804·2021-11-18 10:02
閱讀 3791·2021-09-02 10:21
閱讀 1815·2021-08-27 16:16
閱讀 2122·2019-08-30 15:56
閱讀 2483·2019-08-29 16:53
閱讀 1424·2019-08-29 11:18
閱讀 3033·2019-08-26 10:33
閱讀 2703·2019-08-23 18:34