mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Bug 1162013. Process the Promise queue between adjacent setTimeout callback invocations when we're going through the callback list without returning to the event loop. r=smaug
This commit is contained in:
parent
d383fa3c40
commit
59ea7eac31
@ -12438,6 +12438,12 @@ nsGlobalWindow::RunTimeoutHandler(nsTimeout* aTimeout,
|
||||
// point anyway, and the script context should have already reported
|
||||
// the script error in the usual way - so we just drop it.
|
||||
|
||||
// Since we might be processing more timeouts, go ahead and flush the promise
|
||||
// queue now before we do that. We need to do that while we're still in our
|
||||
// "running JS is safe" state (e.g. mRunningTimeout is set, timeout->mRunning
|
||||
// is false).
|
||||
Promise::PerformMicroTaskCheckpoint();
|
||||
|
||||
if (trackNestingLevel) {
|
||||
sNestingLevel = nestingLevel;
|
||||
}
|
||||
@ -12447,6 +12453,7 @@ nsGlobalWindow::RunTimeoutHandler(nsTimeout* aTimeout,
|
||||
|
||||
mRunningTimeout = last_running_timeout;
|
||||
timeout->mRunning = false;
|
||||
|
||||
return timeout->mCleared;
|
||||
}
|
||||
|
||||
@ -12566,14 +12573,17 @@ nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
|
||||
deadline = now;
|
||||
}
|
||||
|
||||
// The timeout list is kept in deadline order. Discover the latest
|
||||
// timeout whose deadline has expired. On some platforms, native
|
||||
// timeout events fire "early", so we need to test the timer as well
|
||||
// as the deadline.
|
||||
// The timeout list is kept in deadline order. Discover the latest timeout
|
||||
// whose deadline has expired. On some platforms, native timeout events fire
|
||||
// "early", but we handled that above by setting deadline to aTimeout->mWhen
|
||||
// if the timer fired early. So we can stop walking if we get to timeouts
|
||||
// whose mWhen is greater than deadline, since once that happens we know
|
||||
// nothing past that point is expired.
|
||||
last_expired_timeout = nullptr;
|
||||
for (nsTimeout *timeout = mTimeouts.getFirst(); timeout; timeout = timeout->getNext()) {
|
||||
if (((timeout == aTimeout) || (timeout->mWhen <= deadline)) &&
|
||||
(timeout->mFiringDepth == 0)) {
|
||||
for (nsTimeout *timeout = mTimeouts.getFirst();
|
||||
timeout && timeout->mWhen <= deadline;
|
||||
timeout = timeout->getNext()) {
|
||||
if (timeout->mFiringDepth == 0) {
|
||||
// Mark any timeouts that are on the list to be fired with the
|
||||
// firing depth so that we can reentrantly run timeouts
|
||||
timeout->mFiringDepth = firingDepth;
|
||||
|
18
dom/promise/tests/file_promise_and_timeout_ordering.js
Normal file
18
dom/promise/tests/file_promise_and_timeout_ordering.js
Normal file
@ -0,0 +1,18 @@
|
||||
var log = [];
|
||||
var resolvedPromise = Promise.resolve(null);
|
||||
function schedulePromiseTask(f) {
|
||||
resolvedPromise.then(f);
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
log.push('t1start');
|
||||
schedulePromiseTask(function() {
|
||||
log.push('promise');
|
||||
});
|
||||
log.push('t1end');
|
||||
}, 10);
|
||||
|
||||
setTimeout(function() {
|
||||
log.push('t2');
|
||||
postMessage(log.join(', '));
|
||||
}, 10);
|
@ -7,3 +7,7 @@
|
||||
[test_resolve.html]
|
||||
[test_resolver_return_value.html]
|
||||
[test_thenable_vs_promise_ordering.html]
|
||||
[test_promise_and_timeout_ordering.html]
|
||||
support-files = file_promise_and_timeout_ordering.js
|
||||
[test_promise_and_timeout_ordering_workers.html]
|
||||
support-files = file_promise_and_timeout_ordering.js
|
||||
|
15
dom/promise/tests/test_promise_and_timeout_ordering.html
Normal file
15
dom/promise/tests/test_promise_and_timeout_ordering.html
Normal file
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>Test for promise and timeout ordering</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
var t = async_test("Promise callbacks should run immediately after the setTimeout handler that enqueues them");
|
||||
var origPostMessage = window.postMessage;
|
||||
window.postMessage = function(msg) { origPostMessage.call(window, msg, "*"); }
|
||||
window.onmessage = t.step_func_done(function(e) {
|
||||
assert_equals(e.data, "t1start, t1end, promise, t2");
|
||||
});
|
||||
</script>
|
||||
<script src="file_promise_and_timeout_ordering.js"></script>
|
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>Test for promise and timeout ordering in workers</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
var t = async_test("Promise callbacks in workers should run immediately after the setTimeout handler that enqueues them");
|
||||
var w = new Worker("file_promise_and_timeout_ordering.js");
|
||||
w.onmessage = t.step_func_done(function(e) {
|
||||
assert_equals(e.data, "t1start, t1end, promise, t2");
|
||||
});
|
||||
</script>
|
@ -6745,6 +6745,10 @@ WorkerPrivate::RunExpiredTimeouts(JSContext* aCx)
|
||||
}
|
||||
}
|
||||
|
||||
// Since we might be processing more timeouts, go ahead and flush
|
||||
// the promise queue now before we do that.
|
||||
Promise::PerformMicroTaskCheckpoint();
|
||||
|
||||
NS_ASSERTION(mRunningExpiredTimeouts, "Someone changed this!");
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user