<meta charset="utf-8" />
<!-- jQuery -->
<script type="text/javascript" src="js/jquery-1.6.4.min.js"></script>
<!-- CSS -->
<style type="text/css">
div
{
background:#aaa;
width:18px;
height:18px;
position:absolute;
top:10px;
}
</style>
<!-- JavaScript -->
<script>
var funs = [
function() {
$("#block1").animate({left:"+=100"}, 3000, goNext);
},
function() {
$("#block1").css("background","#ff0000");
//暫停 3 秒 (模擬要做 3 秒的事情)
sleep(3000);
goNext();
},
function() {
$("#block1").animate({left:"+=100"},3000);
}
];
$(document).ready(function(){
goNext();
});
function goNext()
{
var fun = funs.shift();
fun();
}
function sleep(milliseconds)
{
var start = new Date().getTime();
while(1)
{
if ((new Date().getTime() - start) > milliseconds)
{
break;
}
}
}
</script>
<div id="block1"></div>
若把 sleep 註解掉就正常了~~ Why??
function() { $("#block1").css("background","#ff0000"); //暫停 3 秒 (模擬要做 3 秒的事情) $("#block1").delay(3000); //用jQuery本身有的函式就行了~==? //sleep(3000); goNext(); }...略...
function sleep( milliseconds ) { var timer = new Date(); var time = timer.getTime(); do{ timer = new Date(); }while( (timer.getTime() - time) < (milliseconds) ); }
瀏覽器reflow/render的速度跟Javascript執行的速度差很多,你用同步的方式實作sleep,會影響到render的執行,所以方格來不及變成紅色,位置也沒有用動畫的方式改變。
像這樣的動作穿插,最好用非同步的方式來做。例如把while改成setTimeout,像這樣:
<pre class="c" name="code">
<meta charset="utf-8" />
<!-- jQuery -->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<!-- CSS -->
<style type="text/css">
div
{
background:#aaa;
width:18px;
height:18px;
position:absolute;
top:10px;
}
</style>
<!-- JavaScript -->
<script>
var funs = [
function() {
$("#block1").animate({left:"+=100"}, 3000, goNext);
},
function() {
$("#block1").css("background","#ff0000");
setTimeout(goNext, 3000);
},
function() {
$("#block1").animate({left:"+=100"},3000);
}
];
$(document).ready(function(){
goNext();
});
function goNext()
{
funs.shift()();
}
</script>
<div id="block1"></div>
經過測試,費大公的改作可以正確執行了,不受jQuery版本的影響。
瀏覽器reflow/render 的速度,這個課題以前都沒有想過耶,費大公可以多說一點,或是哪裡有相關的資料嗎?
請問 fillano 大
若我想要的效果是
(1)執行動畫1
(2)作一些非動畫的事情 (不知道要幾秒)
(3)執行動畫2
按照 (1) -> (2) -> (3) 的時序來執行的話~
要怎做比較好呢?
畢竟不管是 delay 還是 setTimeout
都是已經指明要延遲幾秒..無法代表做一些計算的事情(因為畢竟計算的時間無法估計...因User的電腦等級而定)
有一點我一直很不能理解的是
不知道大家有沒有注意到下列兩行
<pre class="c" name="code">sleep(3000);
goNext();
sleep 是放在 goNext 之前,而 sleep 函數本身是用迴圈實現的 (故會造成 javascript Blocking)
也就是說必須在 sleep 完全執行結束後 才有可能執行 goNext 來加入動畫!
換句話說動畫一定是在 sleep 完全結束後才有可能被加入並執行的~
所以結果理論上次序一定是
(1)加入並執行 "動畫1" (向左移動)
(2)變紅色 並 sleep 3 秒
(3)最後才是加入並執行 "動畫2" (向左移動)
但是真正的結果卻像是第 3 步在第 2 步還沒執行完畢就已經偷跑了
這個部份其實跟Javascript的基本執行機制有關係。
Javascript是以函數為執行的基本單位(函數裡面執行其他函數時,也算在同一個函數內),一個函數沒有執行完畢前,不會做其他的動作(函數)。你程式裡面真正的動作是執行兩次goNext()(第三個goNext是在第二個goNext之中執行的,所以只能算一個),第一次執行完畢後,瀏覽器有機會做reflow,但是第二次的動作其實都包在一個函數中,動作在Javascript中執行完成時,瀏覽器還來不及reflow,所以你只看到funs[1]跟funs[2]中兩個動作的結果(中間過程來不及跑了)。
所以要用Javascript做需要在精確時間完成的動畫,你會需要使用許多的setTimeout,並且在動作中做計時,如果時機過了就要放棄動作,進入下一格。當然,像這樣的動作你可以用alert就把他破壞掉。
我做的事情是:
fillano 大:
fillano提到:
Javascript是以函數為執行的基本單位(函數裡面執行其他函數時,也算在同一個函數內),一個函數沒有執行完畢前,不會做其他的動作(函數)。
這是真的嗎....!?
我寫了下面的程式來測試
<pre class="c" name="code">
<meta charset="utf-8" />
<script type="text/javascript" src="js/jquery-1.6.4.min.js"></script>
<script>
$(document).ready(function(){
fun1();
})
function fun1()
{
fun2();
var tmp=0;
for(var i=0; i<100000; i++)
{
tmp += i*i;
}
var date = new Date();
$("#block1").html(date.getTime());
}
function fun2()
{
var date = new Date();
$("#block2").html(date.getTime());
}
</script>
<div id="block1"></div>
<div id="block2"></div>
結果是 block1 的時間大於 block2~
換句話說 javascript 在 fun1 內 還是會先執行完 fun2 才會往下執行耶~
跟你講的好像不太一樣
我修改了原始的程式~ 加上時間的顯示..來釐清執行順序問題...
可惜 code 字數的關係貼不上來~
但結果顯示 真的是跑完 sleep() 後才往下繼續執行的
我猜想有沒有可能是 jQuery Animate 的關係
if( 第二次動畫的開始時間 - 第一次動畫的結束時間 > 3秒) //也就是jQuery 認為動畫逾時了
{
就直接跳到動畫最後的結果 而不再表演動畫
}
新版的 jQuery 太過聰明..會去計算 動畫逾時 了幾秒...然後決定應該從哪表演起...
所以 聰明反被聰明誤... 反而造成 達不到我要的效果...
反而是舊版ㄉ jQuery 可以達到....orz...
前面這樣講得也不太對。我trace了一下jQuery.fn.animate的執行過程,看起來他的運作方式如下:
所以,需要注意到適時用非同步的方式執行程式,這樣才能讓setInterval有機會執行,不然就有可能一開始執行setInterval時,時間已經過了,所以只跑出結果。
我覺得有爭議的地方在於動畫開始時間的定義~
我猜舊版 jQuery 定義動畫2的開始時間是動畫2剛被加入的時間~
但新版 jQuery 卻把動畫1的結束時間當作是動畫2的開始時間~ orz
這或許是因為我把動畫2 寫在動畫1的 finish callback function 的關係...
光是用時間這樣看不準啦,建議用開發工具的console.log來標示(在函數開始與最後顯示開始與結束)
我前面的圖不太對,你執行的過程應該是:
另外,把第一個funs改成這樣:
<pre class="c" name="code">$("#block1").animate({left:"+=100"}, 3000, function(){console.log('animation 1 end');setTimeout(goNext, 0);});
效果就都會出來。