Last active
May 31, 2023 11:19
-
-
Save john-doherty/ddbf13e625c52c7b8bb9645a39a3fb8b to your computer and use it in GitHub Desktop.
Wait for multiple JavaScript events to fire
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
/** | |
* Waits for multiple DOM events to fire | |
* @example | |
* waitForEvents(window, [ | |
* 'DOMContentLoaded', | |
* 'online' | |
* ]) | |
* .then(function(result) { | |
* // do stuff | |
* }); | |
* @param {object} eventTarget - element to listen for events on (default document) | |
* @param {Array<string>|string} eventNames - array or csv string of event names | |
* @param {boolean} strict - if true, does not resolve until events fire in exact order | |
* @returns {Promise<Array>} resolves with event objects in order | |
*/ | |
function waitForEvents(eventTarget, eventNames, strict) { | |
// Default to document if no eventTarget is provided | |
eventTarget = eventTarget || document; | |
// Convert eventNames to an array if it's not already | |
if (!Array.isArray(eventNames)) { | |
eventNames = String(eventNames).split(','); | |
} | |
// Trim whitespace from event names | |
eventNames = eventNames.map(function(eventName) { | |
return String(eventName).trim(); | |
}); | |
// Throw an error if no valid event names are provided | |
if (eventNames.length <= 0) { | |
throw new Error('Invalid eventNames'); | |
} | |
// Initialize an empty object to store the event objects | |
var eventObjects = {}; | |
// Store the index of the last event that was fired | |
var lastEventIndex = -1; | |
// Create an array of promises, one for each event | |
var listeners = eventNames.map(function(eventName, index) { | |
// Return a promise that resolves once event fired | |
return new Promise(function(resolve) { | |
// Define event handler inside promise | |
function waitForEventHandler(e) { | |
// In strict mode, only resolve the promise when events are fired in order | |
if (strict && index !== lastEventIndex + 1) { | |
// If not in order, store the event but don't resolve the promise | |
eventObjects[e.type] = e; | |
} else { | |
// Remove the event listener once the event has fired | |
eventTarget.removeEventListener(eventName, waitForEventHandler); | |
// Store the event object in the eventObjects | |
eventObjects[e.type] = e; | |
// Update the index of the last fired event | |
lastEventIndex = index; | |
// Resolve the promise | |
resolve(); | |
} | |
} | |
// Add the event listener | |
eventTarget.addEventListener(eventName, waitForEventHandler, false); | |
}); | |
}); | |
// Return a promise that resolves when all events have fired | |
return Promise.all(listeners).then(function() { | |
// Return event objects in the order they were added | |
return eventNames.map(function(name) { | |
return eventObjects[name]; | |
}); | |
}); | |
} |
Added strict
param, if true
does not resolve the promise until all events have fired in order
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Event objects are now returned in the order they were added