คำนำ:
คำตอบอื่น ๆ บางคำตอบถูกต้อง แต่ไม่ได้แสดงให้เห็นจริง ๆ ว่าปัญหาที่แก้แล้วคืออะไรดังนั้นฉันจึงสร้างคำตอบนี้เพื่อนำเสนอภาพประกอบโดยละเอียด
เป็นเช่นนี้ฉันกำลังโพสต์รายละเอียดเดินผ่านของสิ่งที่เบราว์เซอร์ไม่และวิธีการใช้setTimeout()จะช่วยให้ มันดูค่อนข้างยาว แต่จริงๆแล้วเรียบง่ายและตรงไปตรงมา - ฉันเพิ่งทำรายละเอียดมาก
UPDATE:ฉันได้ทำเพื่อ JSFiddle สดแสดงให้เห็นถึงคำอธิบายดังต่อไปนี้: http://jsfiddle.net/C2YBE/31/ ขอบคุณมากที่ @ThangChung ที่ช่วยกันเริ่มต้นมัน
ปรับปรุง 2:ในกรณีที่เว็บไซต์ JSFiddle ตายหรือลบรหัสฉันเพิ่มรหัสในคำตอบนี้ในตอนท้าย
รายละเอียด :
ลองนึกภาพเว็บแอปด้วยปุ่ม "ทำบางสิ่ง" และ div ผลลัพธ์
onClickจัดการสำหรับปุ่ม "ทำอะไร" เรียกฟังก์ชั่น "LongCalc ()" ซึ่งจะสิ่งที่ 2:
ทำการคำนวณที่ยาวมาก (บอกว่าใช้เวลา 3 นาที)
 
พิมพ์ผลลัพธ์ของการคำนวณลงในผลลัพธ์ div
 
ตอนนี้ผู้ใช้ของคุณเริ่มทดสอบสิ่งนี้คลิกปุ่ม "ทำอะไรบางอย่าง" และหน้าเว็บอยู่ที่นั่นโดยไม่ทำอะไรเลยเป็นเวลา 3 นาทีพวกเขากระสับกระส่ายคลิกปุ่มอีกครั้งรอ 1 นาทีไม่มีอะไรเกิดขึ้นคลิกปุ่มอีกครั้ง ... 
ปัญหาชัดเจน - คุณต้องการ "สถานะ" DIV ซึ่งแสดงว่าเกิดอะไรขึ้น เรามาดูกันว่ามันทำงานอย่างไร
ดังนั้นคุณจึงเพิ่ม "สถานะ" DIV (ตอนแรกว่างเปล่า) และแก้ไขonclickตัวจัดการ (ฟังก์ชั่นLongCalc()) เพื่อทำ 4 สิ่ง:
เติมสถานะ "กำลังคำนวณ ... อาจใช้เวลาประมาณ 3 นาที" ในสถานะ DIV
 
ทำการคำนวณที่ยาวมาก (บอกว่าใช้เวลา 3 นาที)
 
พิมพ์ผลลัพธ์ของการคำนวณลงในผลลัพธ์ div
 
เติมสถานะ "การคำนวณเสร็จแล้ว" ลงในสถานะ DIV
 
และคุณยินดีให้แอปแก่ผู้ใช้ในการทดสอบอีกครั้ง
พวกเขากลับมาหาคุณด้วยความโกรธ และอธิบายว่าเมื่อพวกเขาคลิกปุ่มสถานะ DIV จะไม่อัปเดตด้วยสถานะ "กำลังคำนวณ ... " !!!
คุณเกาหัวถามเกี่ยวกับ StackOverflow (หรืออ่านเอกสารหรือ Google) และตระหนักถึงปัญหา:
เบราว์เซอร์ทุกสถานที่ของ "สิ่งที่ต้องทำ" งาน (งาน UI ทั้งสองและคำสั่งจาวาสคริปต์) เป็นผลมาจากเหตุการณ์ที่เกิดขึ้นเป็นคิวเดียว และน่าเสียดายที่การวาดใหม่ "สถานะ" DIV ด้วยค่า "กำลังคำนวณ ... " ใหม่เป็นสิ่งที่ต้องทำแยกต่างหากซึ่งจะไปยังจุดสิ้นสุดของคิว!
นี่คือรายละเอียดของกิจกรรมในระหว่างการทดสอบของผู้ใช้เนื้อหาของคิวหลังจากแต่ละเหตุการณ์:
- คิว: 
[Empty] 
- กิจกรรม: คลิกที่ปุ่ม คิวหลังจากเหตุการณ์:
[Execute OnClick handler(lines 1-4)] 
- เหตุการณ์: เรียกใช้บรรทัดแรกในตัวจัดการ OnClick (เช่นเปลี่ยนค่าสถานะ DIV) 
[Execute OnClick handler(lines 2-4), re-draw Status DIV with new "Calculating" value]คิวหลังจากเหตุการณ์: โปรดทราบว่าขณะที่การเปลี่ยนแปลง DOM เกิดขึ้นทันทีอีกครั้งวาดองค์ประกอบที่สอดคล้องกัน DOM คุณจำเป็นต้องมีเหตุการณ์ใหม่ที่เกิดจากการเปลี่ยนแปลง DOM, ที่ไปในตอนท้ายของคิว 
- ปัญหา!!!  ปัญหา!!! รายละเอียดอธิบายด้านล่าง
 
- เหตุการณ์: เรียกใช้บรรทัดที่สองในตัวจัดการ (การคำนวณ) 
[Execute OnClick handler(lines 3-4), re-draw Status DIV with "Calculating" value]คิวหลัง: 
- เหตุการณ์: เรียกใช้บรรทัดที่ 3 ในตัวจัดการ (เติมผลลัพธ์ DIV) 
[Execute OnClick handler(line 4), re-draw Status DIV with "Calculating" value, re-draw result DIV with result]คิวหลัง: 
- เหตุการณ์: ดำเนินการบรรทัดที่ 4 ในตัวจัดการ (ระบุสถานะ DIV ด้วย "DONE") 
[Execute OnClick handler, re-draw Status DIV with "Calculating" value, re-draw result DIV with result; re-draw Status DIV with "DONE" value]คิว: 
- เหตุการณ์: ดำเนินการโดยนัย
returnจากonclickตัวจัดการย่อย เรานำ "Execute OnClick handler" ออกจากคิวและเริ่มดำเนินการรายการถัดไปในคิว 
- หมายเหตุ: เนื่องจากเราทำการคำนวณเสร็จแล้ว 3 นาทีจึงส่งให้กับผู้ใช้แล้ว กิจกรรมวาดซ้ำยังไม่เกิดขึ้น !!!
 
- กิจกรรม: วาดสถานะใหม่ DIV ด้วยค่า "กำลังคำนวณ" เราทำการวาดใหม่และถอดมันออกจากคิว
 
- เหตุการณ์: วาด DIV ผลลัพธ์อีกครั้งด้วยค่าผลลัพธ์ เราทำการวาดใหม่และถอดมันออกจากคิว
 
- กิจกรรม: วาดสถานะใหม่ DIV ด้วยค่า "เสร็จสิ้น" เราทำการวาดใหม่และถอดมันออกจากคิว ผู้ชมที่มีตาเฉียบอาจสังเกตเห็น "สถานะ DIV ด้วยค่า" การคำนวณ "ที่กระพริบสำหรับเศษเสี้ยวของไมโครวินาที - หลังจากเสร็จสิ้นการคำนวณ
 
ดังนั้นปัญหาพื้นฐานคือเหตุการณ์ re-draw สำหรับ "สถานะ" DIV ถูกวางในคิวในตอนท้ายหลังจากเหตุการณ์ "execute line 2" ซึ่งใช้เวลา 3 นาทีดังนั้นการวาดใหม่จริงจะไม่เกิดขึ้นจนกว่า หลังจากการคำนวณเสร็จสิ้น
setTimeout()เพื่อช่วยเหลือมา มันช่วยได้อย่างไร เพราะด้วยการเรียกใช้โค้ดที่ทำงานแบบยาวผ่านทางsetTimeoutจริง ๆ คุณสร้าง 2 เหตุการณ์: setTimeoutการดำเนินการเองและ (เนื่องจากหมดเวลา 0), รายการคิวแยกต่างหากสำหรับรหัสที่กำลังดำเนินการ
ดังนั้นเพื่อแก้ไขปัญหาของคุณคุณแก้ไขonClickhandler ของคุณให้เป็นคำสั่ง TWO (ในฟังก์ชั่นใหม่หรือเพียงแค่บล็อกภายในonClick):
เติมสถานะ "กำลังคำนวณ ... อาจใช้เวลาประมาณ 3 นาที" ในสถานะ DIV
 
ดำเนินการsetTimeout()ด้วย 0 หมดเวลาและโทรออกไปยังLongCalc()ฟังก์ชั่น
LongCalc()ฟังก์ชั่นเกือบเหมือนครั้งที่แล้ว แต่เห็นได้ชัดว่าไม่มีสถานะ "กำลังคำนวณ ... " การอัปเดต DIV เป็นขั้นตอนแรก และเริ่มการคำนวณแทนทันที
 
ดังนั้นลำดับเหตุการณ์และคิวจะเป็นอย่างไรตอนนี้
- คิว: 
[Empty] 
- กิจกรรม: คลิกที่ปุ่ม คิวหลังจากเหตุการณ์:
[Execute OnClick handler(status update, setTimeout() call)] 
- เหตุการณ์: เรียกใช้บรรทัดแรกในตัวจัดการ OnClick (เช่นเปลี่ยนค่าสถานะ DIV) 
[Execute OnClick handler(which is a setTimeout call), re-draw Status DIV with new "Calculating" value]คิวหลังจากเหตุการณ์: 
- เหตุการณ์: เรียกใช้บรรทัดที่สองในตัวจัดการ (การโทร setTimeout) 
[re-draw Status DIV with "Calculating" value]คิวหลัง: คิวไม่มีอะไรใหม่อยู่ในนั้นอีก 0 วินาที 
- เหตุการณ์: การเตือนภัยจากการหมดเวลาใช้งานจะดับลง 0 วินาทีต่อมา 
[re-draw Status DIV with "Calculating" value, execute LongCalc (lines 1-3)]คิวหลัง: 
- เหตุการณ์: ใหม่วาด DIV สถานะด้วย "คำนวณ" ค่า 
[execute LongCalc (lines 1-3)]คิวหลัง: โปรดทราบว่าเหตุการณ์วาดใหม่นี้อาจเกิดขึ้นจริงก่อนที่สัญญาณเตือนจะดับซึ่งทำงานได้ดีเช่นกัน 
- ...
 
ไชโย! Status DIV เพิ่งได้รับการอัปเดตเป็น "กำลังคำนวณ ... " ก่อนการคำนวณเริ่ม !!!
ด้านล่างเป็นตัวอย่างโค้ดจาก JSFiddle ที่แสดงตัวอย่างเหล่านี้: http://jsfiddle.net/C2YBE/31/ :
รหัส HTML:
<table border=1>
    <tr><td><button id='do'>Do long calc - bad status!</button></td>
        <td><div id='status'>Not Calculating yet.</div></td>
    </tr>
    <tr><td><button id='do_ok'>Do long calc - good status!</button></td>
        <td><div id='status_ok'>Not Calculating yet.</div></td>
    </tr>
</table>
รหัส JavaScript: (ดำเนินการonDomReadyและอาจต้องใช้ jQuery 1.9)
function long_running(status_div) {
    var result = 0;
    // Use 1000/700/300 limits in Chrome, 
    //    300/100/100 in IE8, 
    //    1000/500/200 in FireFox
    // I have no idea why identical runtimes fail on diff browsers.
    for (var i = 0; i < 1000; i++) {
        for (var j = 0; j < 700; j++) {
            for (var k = 0; k < 300; k++) {
                result = result + i + j + k;
            }
        }
    }
    $(status_div).text('calculation done');
}
// Assign events to buttons
$('#do').on('click', function () {
    $('#status').text('calculating....');
    long_running('#status');
});
$('#do_ok').on('click', function () {
    $('#status_ok').text('calculating....');
    // This works on IE8. Works in Chrome
    // Does NOT work in FireFox 25 with timeout =0 or =1
    // DOES work in FF if you change timeout from 0 to 500
    window.setTimeout(function (){ long_running('#status_ok') }, 0);
});