20191227
js原生部分
setTimeout與setInterval在不一樣瀏覽器下的差別
(一)IE系列中的setTimeout
首先,咱們看看微軟出的DHTML參考手冊中是如何說的:
setTimeout Method
Evaluates an expression after a specified number of milliseconds has elapsed.
Syntax
iTimerID = window.setTimeout(vCode, iMilliSeconds \[, sLanguage\])
Parameters
vCode Required. Variant that specifies the function pointer or string that indicates
the code to be executed when the specified interval has elapsed.
iMilliSeconds Required. Integer that specifies the number of milliseconds.
sLanguage Optional. String that specifies one of the following values:
JScript Language is JScript.
VBScript Language is VBScript.
JavaScript Language is JavaScript.
MSDN上關於setTimeout的說明:
http://msdn.microsoft.com/en-us/library/ms536753(VS.85).aspx
也就是說,setTimeout接收3個參數,第3個參數表示腳本語言的類型,若是你再傳入更多的參數,是無心義的。
所以,在IE中,如下兩種都是對的。
JavaScript code
?
1
2
3
setTimeout('alert(1)', 50);
setTimeout('msgbox "終止、重試、忽略,您看着辦吧。", vbAbortRetryIgnore + vbDefaultButton2, "告訴您"', 50, 'VBScript');
(二)Mozilla系列中的setTimeout
咱們看看Mozilla官方網站上 Gecko DOM Reference 手冊中是如何說的:
window.setTimeout
Summary
Executes a code snippet or a function after specified delay.
Syntax
var timeoutID = window.setTimeout(func, delay, \[param1, param2, ...\]);
var timeoutID = window.setTimeout(code, delay);
前兩個參數都同樣,沒差異,從第三個參數就不一樣了。
由於目前只有IE瀏覽器支持多種語言的腳本,其它瀏覽器只支持js腳本因此不須要傳語言類型的參數。
Mozilla把傳給setTimeout的第3個以及更後面的更多參數依次的傳給前面的func作爲參數。
Firefox, Opera, Safari, Chrome等等也都是如此。
可是注意到,Mozilla上說了他家的setTimeout有一個叫作"Lateness" argument的BUG.
"Lateness" argument
Functions invoked by setTimeout are passed an extra "lateness" argument in Mozilla,
i.e., the lateness of the timeout in milliseconds. (See bug 10637 and bug 394769.)
這就是開頭那個例子中,Firefox(3.0)下有一個烏龍數字的根源。
Mozilla上關於setTimeout的說明:
https://developer.mozilla.org/en/DOM/window.setTimeout
(三)其它瀏覽器系列(Opera, Safari, Chrome)中的setTimeout
和Mozilla系列中的基本同樣,可是沒有Mozilla系列中的多一個參數的BUG.
武林外傳:使用setTimeout的小技巧
(1)IE中給setTimeout中的調用函數傳參數
上面的分析可知,IE是不支持在setTimeout中給被調用的函數傳參數的,爲了瀏覽器世界的和諧,咱們能夠把函數調用參數包裹進新的匿名函數中。示例:
function f(a){
alert(a);
}
// setTimeout(f,50,'hello'); //用於非IE
setTimeout(function(){f('hello')},50); //通用
var str='hello';
setTimeout(function(){f(str)},50); //通用
(2)this問題
setTimeout調用的函數被執行時的上下文是全局,而再也不是調用setTimeout方法時的上下文。因此,setTimeout的第一個參數的函數被執行時其this是指向window的,若是須要保留調用setTimeout方法時的this,就須要把當時的this傳進去。示例:
function Person(name){
this.name=name;
var f=function(){alert('My name is '+this.name)};
// setTimeout(f,50); //錯誤
var THIS=this;
setTimeout(function(){f.apply(THIS)},50); //正確,通用
setTimeout(function(){f.call(THIS)},50); //正確,通用
}
new Person('Jack');
alert()底層是如何實現的?
JS BOM api 中 alert 的實現
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 線程來收發消息。畢竟用戶操做基本上是異步的,總得響應操做事件,這個不難理解吧。
若是,開啓模態窗口後續操做禁止了,那麼有幾種可能性:
執行線程終止
執行線程被 sleep
無視MessageLoop(也就是不響應用戶操做事件)
前兩個可想而知,執行線程終止或sleep,那就啥都別幹了,比如同步AJAX 鎖死界面了。
第三個也是鎖死界面,可是有緩。
爲啥呢,起碼 開啓的 alert UI 能夠本身內部開個消息線程來接替主消息循環接收用戶輸入響應就行了。
都知道的,消息線程其實就是個有條件退出的死循環。等用戶點擊肯定啊,關閉啊,它就到達退出條件了,而後把主消息循環恢復,主界面又能夠響應用戶操做了,而後關閉(擦除)自身UI就行了。
這裏有個小細節,就是模態窗口阻塞代碼的事兒。這不是絕對的(這裏說的是瀏覽器JS實現的模態)。
好比:
BX9015: setTimeout 和 setInteval 在各瀏覽器中被對話框阻塞的狀況不一樣
細節上來講,這可能取決於alert內消息循環實現,這個 while(true) 是否處於主代碼執行以前,仍是另開了線程來異步循環的。
如:
主UI代碼
....
alert()
內部
while(true){
....
}
主 UI 後續代碼
一旦如此實現,可見,在alert 的內部消息循環有條件退出前,主代碼會被阻塞。