/parallel-data

Speed up the loading of your application by loading its required data in parallel to your app code!

Primary LanguageJavaScriptMIT LicenseMIT

ParallelData

The Problem 🐌

When building client heavy apps or single page apps (SPAs), the most common way to structure the load of your application is:

-> Request HTML
...
---> Request all CSS
---> Request all Javascript
...
------> JS is ready and executing; app is initializing
-------> Request Required App Data
...
-----------> App Data is all ready, present the full app to the user

The requesting of JS and CSS is usually handled in parallel - whoohoo. When that's ready, your app parses and starts executing but you have logic that requires some data to be loaded before it continues to present the full version of the app. That data could be user info/permissions data, app/domain specific data, or any type of data that you require before presenting the final version of your app. But if you look at the flows, we keep the information about fetching the data inside the app code meaning we require the user to wait until the app code is executing, requests the data, and processes the data request before it can continue.

What if we could speed up our app and request the required app data at the same time as when you request the app assets?

HTTP2 Push 🌟

The HTTP2 Push capabilities are 100% targeted at solving these problems and that's awesome. But for some, using HTTP2 is not a available or a practical option - that's where ParallelData comes in.

A Solution ⚡️

ParallelData gives you a drop in JavaScript snippet that allows you to define the data urls you want to request and it will request them immediately (in parallel with your main JS/CSS downloads). Without changing anything in your app code, your app's next requests for those endpoints will be given the responses as they were received when ParallelData received them. With that your app is now faster and no longer waiting for your app to load, parse, and initialize to start requesting it's data!

Note 🗒

The scope of ParallelData is limited to loading data in parallel. For prefetching/preloading assets (css, js, images, etc.) I would look into resource hints/prioritization: spec and web fundamentals

Request/Response Scenarios 🔄

  • If ParallelData has received the endpoint response before your app requests it, your app requests will immediately get the responses and respective events.
  • If ParallelData has not received the endpoint response before your app requests it, your app requests will get the responses and respective events when the original ParallelData responses are received.

Networking Options Support ✅

  • XHR support (GET requests only)
  • Sending Headers (per request or for all requests)
  • Fetch support (GET requests only)

Please create an issue if there are more use-cases that make sense for ParallelData to support

Browser Support 🌐

ParallelData is tested and works in IE 9+, Chrome, FireFox, Safari, and all modern mobile browsers.


How To Use 👍🏻

  • Pick the version you want to use on your site from the dist directory
  • Copy that version's code into your HTML file for your app
  • Below that, start using the ParallelData API

The API ⚒

ParallelData.getForXHR( url, options )

This method immediately kicks off a GET request to the specified URL with the provided options. Note, this only matches requests that are XMLHttpRequest based.

Function Parameters

  • url - the url to load in parallel. This must exactly match the url used when requesting data in the app
  • options - an object specifying request configuration
    • options.headers - an object specifying the request headers to be added
    • options.onParallelDataResponse - a function callback that is called when the XHR request's readystate is complete. We will pass in the XHR in the first parameter and a ParallelData context object that can be used to know if the request was already handed off to the app.

ParallelData.getForFetch( url, options )

This method immediately kicks off a GET request to the specified URL with the provided options. Note, this only matches requests that are window.fetch based. By using this function, we assume that your app uses window.fetch if it is available and falls back to XMLHttpRequest for requests if it is not. With that, ParallelData will do the same. If you use this function and window.fetch is not available, we will automatically fallback to calling ParallelData.getForXHR internally for you.

Function Parameters

  • url - the url to load in parallel. This must exactly match the url used when requesting data in the app.
  • options - an object specifying request configuration. We allow the full set of options that window.fetch allows.
    • Note, options.credentials is set to "include" by default and options.redirect is set to "follow" by default
  • options.onParallelDataResponse - a function callback that is called when the Fetch promise resolves. We will pass in the fetch response object in the first parameter and a ParallelData context object that can be used to know if the request was already handed off to the app.

ParallelData.configure( configOptions )

This method allows you to specify configuration at the library level. Currently, it's primary use is for setting options (like common headers) that should be used for all requests - allowing you to omit adding those options for each getForFetch() or getForXHR() call.

Function Parameters

  • configOptions - an object specifying configuration for ParallelData
    • configOptions.allRequests - an object specifying options to be applied to all requests
      • configOptions.allRequests.headers - an object specifying the headers to be added to all requests

Running examples 🏃

Web

Locally

Building library locally 🔨

  • Clone this repo locally
  • Build options:
    • Run npm run dev to watch files and perform a build
    • Run npm run build to run a single build
  • Run examples locally to have quick access to sites that are running the built library

Testing library 🔍

The tests for this library are interactive visual tests. This was decided because I did not want any testing framework to override anything in an non-browser fashion causing the results of the tests to hide something.

Web

Locally