-
-
Save joepie91/89ad2ae0855a787dc08504188b2bc8f7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
const Promise = require("bluebird"); | |
const createEventEmitter = require("create-event-emitter"); | |
const ms = require("ms"); | |
/* | |
This timer is meant for usecases where eg. you want to display a particular "loading" message after a certain amount of loading time, but *when* the loading message is displayed it must be visible for at least a certain amount of time, to prevent a visually jarring experience. | |
This is accomplished by employing two timing periods, for example: | |
0ms 100ms 200ms | |
|------------------------|-------------------------|------ --- --- -- -- - - | |
\________________________/\________________________/ | |
Activation delay, 100ms Completion delay, 200ms | |
\_______________________/│\_______________________/│\_____ ___ ___ __ __ _ _ | |
No waiting │ Waiting occurs here │ No waiting | |
│ │ | |
│ └ Waits until here | |
│ (where applicable) | |
└ "activated" event fires here | |
After the 'activation delay' expires, an 'activated' event is emitted that can be used to know when to eg. display a loading message. The 'completion delay' is used to determine how long to wait before switching to the next view. | |
Crucially, the behaviour of the `await` method varies depending on whether the timer is in the activation-delay or completion-delay phase; while in the activation-delay phase, `await` will resolve immediately (as no loading UI has been shown yet), whereas in the completion-delay phase, it is only resolved after the completion delay has finished (or immediately, if `await` is called *after* already finishing the completion delay). | |
To recap: | |
- Between 0ms and 100ms, `await` will resolve immediately. | |
- Between 100ms and 200ms, `await` will resolve after (200ms - passedTime) milliseconds. | |
- After 200ms, `await` will resolve immediately. | |
This means that it's safe to wire up a view change to the `await` Promise; it will only wait if there's a completion delay to wait out, and otherwise the view change will happen instantly. | |
Once your loading process has completed, you should call the `disregard` method on the timer; this will prevent the 'activated' event from firing if you were still in the activation-delay phase when the loading completed. | |
*/ | |
module.exports = function createStaggeredDelayTimer(activationDelay, completionDelay, baseTime = Date.now()) { | |
let doneAt = baseTime + ms(completionDelay); | |
let activated = false; | |
let disregarded = false; | |
let emitter = createEventEmitter({ | |
await: function awaitStaggeredDelayTimer() { | |
return Promise.try(() => { | |
if (activated === true && doneAt > Date.now()) { | |
return Promise.delay(doneAt - Date.now()); | |
} | |
}); | |
}, | |
disregard: function disregardStaggeredDelayTimer() { | |
disregarded = true; | |
} | |
}); | |
setTimeout(() => { | |
if (disregarded === false) { | |
emitter.emit("activated"); | |
activated = true; | |
} | |
}, ms(activationDelay)); | |
return emitter; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment