HTML5 ドラフト仕様では、setTimeout メソッドを非同期で実行できると述べています (コールバックが実行される順序が保持されない可能性があることを暗示しています)。これは、ブラウザーが行っていることである可能性があります。
...
6. ハンドルを返し、このアルゴリズムを非同期で実行し続けます。
7. メソッド コンテキストが Window オブジェクトの場合、メソッド コンテキストに関連付けられた Document が完全にアクティブになるまで、さらにタイムアウトミリ秒待機します (連続する必要はありません)。
いずれにせよ、次のようなことを行うことで、この問題を回避できます。
function inOrderTimeout(/* func1[, func2, func3, ...funcN], timeout */)
{ var timer; // for timeout later
var args = arguments; // allow parent function arguments to be accessed by nested functions
var numToRun = args.length - 1; // number of functions passed
if (numToRun < 1) return; // damm, nothing to run
var currentFunc = 0; // index counter
var timeout = args[numToRun]; // timeout should be straight after the last function argument
(function caller(func, timeout) // name so that recursion is possible
{ if (currentFunc > numToRun - 1)
{ // last one, let's finish off
clearTimeout(timer);
return;
}
timer = setTimeout(function ()
{ func(); // calls the current function
++currentFunc; // sets the next function to be called
caller(args[currentFunc], timeout);
}, Math.floor(timeout));
}(args[currentFunc], timeout)); // pass in the timeout and the first function to run
}