成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

調(diào)試時經(jīng)常使用的console.log()的同步和異步問題

Coly / 1735人閱讀

摘要:最近幫助一個同學在調(diào)試問題的時候,的輸出真的讓我詫異了一把,因為它竟然會出現(xiàn)異步輸出的情況,因而誤導了我們的判斷,找錯了方向,耽誤了很多時間,所以這里記錄一下遇到的這個問題,加深印象。但調(diào)試對象時,最好還是使用打斷點這樣的方式來調(diào)試更好。

最近幫助一個同學在調(diào)試問題的時候,console.log()的輸出真的讓我詫異了一把,因為它竟然會出現(xiàn)異步輸出的情況,因而誤導了我們的判斷,找錯了方向,耽誤了很多時間,所以這里記錄一下遇到的這個問題,加深印象。

問題現(xiàn)象:

正常輸出:

異常輸出:

我們可以發(fā)現(xiàn),異常輸出的時候,沒展開的時候,顯示的name值是Tom,點擊箭頭展開對象里的name則是Jack,而且,此時的輸出值Jack執(zhí)行語句,明顯是在賦值語句obj.per.name = "Jack"之前調(diào)用的,展開的時候,卻變成了Jack,明顯有些異常,是不是很神奇?我剛遇到這個問題的時候,也是懵逼狀態(tài)的。

為什么會出現(xiàn)這個異常輸出呢?

異常出現(xiàn)原因分析

在分析之前,我們得知道一點,JS中對象是引用類型,每次使用對象時,都只是使用了對象在堆中的引用。

當我們在使用obj.per.name = "Jack"改變了對象的屬性值時,它在堆中name的值也變成了"Jack",而當我們不展開對象看的時候,console.log打印的是對象當時的快照,所以我們看到的name屬性值是沒改變之前的"Tom",展開對象時,它其實是重新去內(nèi)存中讀取對象的屬性值,所以當我們展開對象后看到的name屬性值是Jack。

瀏覽器或者可以說是開發(fā)者工具為什么會有這樣的表現(xiàn)?

這個問題在《你不知道的javascript中卷》第二部分異步和性能1.1節(jié)異步控制臺部分有提及:

There is no specification or set of requirements around how the console.* methods work -- they are not officially part of JavaScript, but are instead added to JS by the hosting environment (see the Types & Grammar title of this book series).
So, different browsers and JS environments do as they please, which can sometimes lead to confusing behavior.
In particular, there are some browsers and some conditions that console.log(..) does not actually immediately output what it"s given. The main reason this may happen is because I/O is a very slow and blocking part of many programs (not just JS). So, it may perform better (from the page/UI perspective) for a browser to handle console I/O asynchronously in the background, without you perhaps even knowing that occurred.

翻譯:

并沒有什么規(guī)范或一組需求指定console.* 方法族如何工作——它們并不是JavaScript 正式的一部分,而是由宿主環(huán)境(請參考本書的“類型和語法”部分)添加到JavaScript 中的。因此,不同的瀏覽器和JavaScript 環(huán)境可以按照自己的意愿來實現(xiàn),有時候這會引起混淆。
尤其要提出的是,在某些條件下,某些瀏覽器的console.log(..) 并不會把傳入的內(nèi)容立即輸出。出現(xiàn)這種情況的主要原因是,在許多程序(不只是JavaScript)中,I/O 是非常低速的阻塞部分。所以,(從頁面/UI 的角度來說)瀏覽器在后臺異步處理控制臺I/O 能夠提高性能,這時用戶甚至可能根本意識不到其發(fā)生。

書中還了個例子:

var a = {
    index: 1
};
// 然后
console.log( a ); // ??
// 再然后
a.index++;

我們通常認為恰好在執(zhí)行到console.log(..) 語句的時候會看到a 對象的快照,打印出類似于{ index: 1 } 這樣的內(nèi)容,然后在下一條語句a.index++ 執(zhí)行時將其修改,這句的執(zhí)行會嚴格在a 的輸出之后。

多數(shù)情況下,前述代碼在開發(fā)者工具的控制臺中輸出的對象表示與期望是一致的。但是,這段代碼運行的時候,瀏覽器可能會認為需要把控制臺I/O 延遲到后臺,在這種情況下,等到瀏覽器控制臺輸出對象內(nèi)容時,a.index++ 可能已經(jīng)執(zhí)行,因此會顯示{ index: 2 }。

到底什么時候控制臺I/O 會延遲,甚至是否能夠被觀察到,這都是游移不定的。

所以如果在調(diào)試的過程中遇到對象在console.log(..) 語句之后被修改,可你卻看到了意料之外的結(jié)果,要意識到這可能是這種I/O 的異步化造成的。

書中建議:

如果遇到這種少見的情況,最好的選擇是在JavaScript 調(diào)試器中使用斷點,而不要依賴控制臺輸出。次優(yōu)的方案是把對象序列化到一個字符串中,以強制執(zhí)行一次“快照”,比如通過JSON.stringify(..)。
結(jié)論

由此可見,console.log打印出來的內(nèi)容并不是一定百分百可信的內(nèi)容。一般對于基本類型number、string、boolean、null、undefined的輸出是可信的。但對于Object等引用類型來說,則就會出現(xiàn)上述異常打印輸出。

所以對于一般基本類型的調(diào)試,調(diào)試時使用console.log來輸出內(nèi)容時,不會存在坑。但調(diào)試對象時,最好還是使用打斷點(debugger)這樣的方式來調(diào)試更好。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/95327.html

相關(guān)文章

  • JavaScript是如何工作:事件循環(huán)異步編程崛起+ 5種使用 async/await 更

    摘要:事件循環(huán)從回調(diào)隊列中獲取并將其推入調(diào)用堆棧。執(zhí)行從調(diào)用堆棧中移除從調(diào)用堆棧中移除快速回顧值得注意的是,指定了事件循環(huán)應該如何工作,這意味著在技術(shù)上它屬于引擎的職責范圍,不再僅僅扮演宿主環(huán)境的角色。 此篇是 JavaScript是如何工作的第四篇,其它三篇可以看這里: JavaScript是如何工作的:引擎,運行時和調(diào)用堆棧的概述! JavaScript是如何工作的:深入V8引擎&編寫...

    Honwhy 評論0 收藏0
  • 現(xiàn)代JS中流程控制:詳解Callbacks 、Promises 、Async/Await

    摘要:控制臺將顯示回調(diào)地獄通常,回調(diào)只能由一個異步函數(shù)調(diào)用。更多資源使更友好規(guī)范使用異步函數(shù)簡化異步編碼旅程異步編程是一項在中無法避免的挑戰(zhàn)。 JavaScript經(jīng)常聲稱是_異步_。那是什么意思?它如何影響發(fā)展?近年來這種方法有何變化? 請思考以下代碼: result1 = doSomething1(); result2 = doSomething2(result1); 大多數(shù)語言都處理每...

    shadowbook 評論0 收藏0
  • 現(xiàn)代JS中流程控制:詳解Callbacks 、Promises 、Async/Await

    摘要:控制臺將顯示回調(diào)地獄通常,回調(diào)只能由一個異步函數(shù)調(diào)用。更多資源使更友好規(guī)范使用異步函數(shù)簡化異步編碼旅程異步編程是一項在中無法避免的挑戰(zhàn)。 JavaScript經(jīng)常聲稱是_異步_。那是什么意思?它如何影響發(fā)展?近年來這種方法有何變化? 請思考以下代碼: result1 = doSomething1(); result2 = doSomething2(result1); 大多數(shù)語言都處理每...

    oujie 評論0 收藏0
  • 現(xiàn)代JS中流程控制:詳解Callbacks 、Promises 、Async/Await

    摘要:控制臺將顯示回調(diào)地獄通常,回調(diào)只能由一個異步函數(shù)調(diào)用。更多資源使更友好規(guī)范使用異步函數(shù)簡化異步編碼旅程異步編程是一項在中無法避免的挑戰(zhàn)。 JavaScript經(jīng)常聲稱是_異步_。那是什么意思?它如何影響發(fā)展?近年來這種方法有何變化? 請思考以下代碼: result1 = doSomething1(); result2 = doSomething2(result1); 大多數(shù)語言都處理每...

    anquan 評論0 收藏0
  • javascript之異步函數(shù)

    摘要:所以增加了異步函數(shù),提高了代碼可讀性,對不太熟悉的人而言,幫助就更大了。因為異步函數(shù)去掉了所有回調(diào)。這就是此代碼有效的原因它和以下一樣代碼更易讀正如上面示例所見,與回調(diào)和代碼相比,異步函數(shù)代碼看起來非常簡單。 這篇文章詳細講解了JavaScript中的異步函數(shù)。 JavaScript中的異步代碼在很短的時間內(nèi)從回調(diào)發(fā)展為Promise,再到ES2017的異步函數(shù),現(xiàn)在我們可以像編寫同步...

    WrBug 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<