This repository was archived by the owner on Dec 15, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 57
/
Copy pathdefault-scheduler.js
70 lines (63 loc) · 2.49 KB
/
default-scheduler.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// If the scheduler is not customized via `etch.setScheduler`, an instance of
// this class will be used to schedule updates to the document. The
// `updateDocument` method accepts functions to be run at some point in the
// future, then runs them on the next animation frame.
module.exports = class DefaultScheduler {
constructor () {
this.updateRequests = []
this.readRequests = []
this.pendingAnimationFrame = null
this.performUpdates = this.performUpdates.bind(this)
this.performingUpdates = false
}
// Enqueues functions that write to the DOM to be performed on the next
// animation frame. Functions passed to this method should *never* read from
// the DOM, because that could cause synchronous reflows.
updateDocument (fn) {
this.updateRequests.push(fn)
if (!this.pendingAnimationFrame) {
this.pendingAnimationFrame = window.requestAnimationFrame(this.performUpdates)
}
}
readDocument (fn) {
this.readRequests.push(fn)
if (!this.pendingAnimationFrame) {
this.pendingAnimationFrame = window.requestAnimationFrame(this.performUpdates)
}
}
// Returns a promise that will resolve at the end of the next update cycle,
// after all the functions passed to `updateDocument` and `updateDocumentSync`
// have been run.
getNextUpdatePromise () {
if (!this.nextUpdatePromise) {
this.nextUpdatePromise = new Promise(resolve => {
this.resolveNextUpdatePromise = resolve
})
}
return this.nextUpdatePromise
}
// Performs all the pending document updates. If running these update
// functions causes *more* updates to be enqueued, they are run synchronously
// in this update cycle without waiting for another frame.
performUpdates () {
while (this.updateRequests.length > 0) {
this.updateRequests.shift()()
}
// We don't clear the pending frame until all update requests are processed.
// This ensures updates requested within other updates are processed in the
// current frame.
this.pendingAnimationFrame = null
// Now that updates are processed, we can perform all pending document reads
// without the risk of interleaving them with writes and causing layout
// thrashing.
while (this.readRequests.length > 0) {
this.readRequests.shift()()
}
if (this.nextUpdatePromise) {
let resolveNextUpdatePromise = this.resolveNextUpdatePromise
this.nextUpdatePromise = null
this.resolveNextUpdatePromise = null
resolveNextUpdatePromise()
}
}
}