js中alert函數的實現原理是什麼?

為什麼alert執行後,對話框顯示在最前,並且禁止了頁面其他的操作?


alert 不是 js 核心的函數

js 一共 7+ 個全局函數:escape( )、eval( )、isFinite( )、isNaN( )、parseFloat( )、parseInt( )、unescape( )…… 但是不包括 alert。

alert 是 BOM 中的成員函數,具體說是 window.alert。

對話框顯示在最前,並且禁止了頁面其他的操作

對話框有兩種,一種是模態,一種是非模態。很顯然 window.alert 函數彈出的對話框是模態的。由於 js 沒有 IO(輸入輸出),所以瀏覽器的 window 對象提供了兩個函數,alert(對應O),prompt (對應 I)。


內個……

這個問題貌似包含兩個意思:

  1. JS BOM api 中 alert 的實現
  2. GUI 中模態窗口阻塞其他代碼運行原理

一個個來說

第一個比較簡單。

首先它是目標平台的包裝函數,也就是非JS原生 API。

這需要調用JS 引擎的包裝方法來作,也就是JS引擎(一般是C++ Lib)會給出一些用來把目標平台業務API(函數)包裝為可使用JS語法調用的機制。

比如 Qt C++ 方法:

QScriptValue ScriptBinding::alert(QScriptContext *context, QScriptEngine *interpreter)
{
...

QMessageBox messageBox;
messageBox.information(NULL,
"App Message:",
message,
QMessageBox::Yes, QMessageBox::Yes);

return QScriptValue::UndefinedValue;
}

這個方法實際上是調用了一個GUI模態窗口,實現基於 Qt 的 alert 提示。

然後使用JS 引擎相關方法把它包裝到JS的全局對象中。

// 獲取JS引擎
QScriptEngine engine = new QScriptEngine();

// 獲取JS全局環境
globalObject = engine-&>globalObject();
QScriptValue nativeMathod;

// 引擎包裝一個新方法,執行這個方法時候將調用 C++ 的alert函數
nativeMathod = engine-&>newFunction(ScriptBinding::alert);

// 把這個包裝好的alert方法放到JS全局環境中
globalObject.setProperty("alert", nativeMathod, QScriptValue::ReadOnly | QScriptValue::Undeletable);

這樣,C++ 實現的 alert 方法就被包裝到 js 中。在js 全局調用 alert 就可以談出對話框。

第二個比較複雜,不好用既有代碼表述。

盡量簡單的來描述下。

基於 GUI 的系統呢,其 UI 部分會有個 EventLoop(真不想用這個詞兒……) 或者 MessageLoop 線程來收發消息。畢竟用戶操作基本上是非同步的,總得響應操作事件,這個不難理解吧。

如果,開啟模態窗口後續操作禁止了,那麼有幾種可能性:

  1. 執行線程終止

  2. 執行線程被 sleep
  3. 無視MessageLoop(也就是不響應用戶操作事件)

前兩個可想而知,執行線程終止或sleep,那就啥都別幹了,好比同步AJAX 鎖死界面了。

第三個也是鎖死界面,但是有緩。

為啥呢,起碼 開啟的 alert UI 可以自己內部開個消息線程來接替主消息循環接收用戶輸入響應就好了。

都知道的,消息線程其實就是個有條件退出的死循環。等用戶點擊確定啊,關閉啊,它就到達退出條件了,然後把主消息循環恢復,主界面又可以響應用戶操作了,然後關閉(擦除)自身UI就好了。

這裡有個小細節,就是模態窗口阻塞代碼的事兒。這不是絕對的(這裡說的是瀏覽器JS實現的模態)。

比如:

BX9015: setTimeout 和 setInteval 在各瀏覽器中被對話框阻塞的情況不同

細節上來說,這可能取決於alert內消息循環實現,這個 while(true) 是否處於主代碼執行之前,還是另開了線程來非同步循環的。

如:

主UI代碼
....
alert()
內部
while(true){
....
}
主 UI 後續代碼

一旦如此實現,可見,在alert 的內部消息循環有條件退出前,主代碼會被阻塞。


推薦閱讀:

請問js非同步和同步載入在性能優化中有什麼區別?
vs code中,寫在<script></script>里的js代碼沒提示么?
請問如何學習nodejs並且達到能開發類似fis,spm的水平 有好的教程嗎?
對於前端,有哪些好的chrome插件或應用可以使用?
HTML & CSS 現在還多人用嗎?

TAG:前端開發 | JavaScript |