npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

beforeunload-request

v1.0.1

Published

A unified API to reliably send data on beforeunload.

Downloads

4,253

Readme

beforeunload-request

A unified API to reliably send data on beforeunload.

Why

There is often a need to send data to a server before a page is closed. Asynchronous XHR requests aren't guaranteed to be sent in such a scenario, so traditionally developers have used synchronous XHR requests. However, due to the poor user experience that synchronous XHR requests on beforeunload cause, browsers have started disallowing them. There are alternatives to synchronous XHR (navigator.sendBeacon and fetch with keepalive), but these new APIs have their own set of quirks and browser issues.

This library unifies all available methods into a single API that prevents common pitfalls (see Methodology).

Installation

$ npm install beforeunload-request

Usage

import beforeunloadRequest from 'beforeunload-request';

const success = beforeunloadRequest(url, options);

Parameters

| Option | Description | Default | | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | | url | URL to send request to (required). | | | options | RequestInit object. The entire object is passed to fetch, however, only the options listed below are considered for sendBeacon and XMLHttpRequest. | | | options.method | HTTP method to use. | 'POST' | | options.headers | Object of HTTP headers to use. | null | | options.body | A string or BodyInit type for the data to send. No automatic conversion of any kind is done (e.g. you must convert to JSON or to URL encoded values yourself). | null | | options.credentials | A RequestCredentials string for the credentials mode to use. | 'include' |

Return value

The function returns a boolean indicating if the request was successful, with one important caveat: if fetch is used, it will always return true; it's impossible to synchronously know if a fetch will result in an error. Otherwise, false guarantees the request did not go through.

Examples

Simple POST request

beforeunloadRequest('/flushSession');

PUT with JSON

beforeunloadRequest('/save', {
	method: 'PUT',
	body: JSON.stringify(data),
	headers: {
		'Content-Type': 'application/json'
	}
});

Using the return value

window.addEventListener('beforeunload', event => {
	const success = beforeunloadRequest('/save', {
		method: 'PUT',
		body: JSON.stringify(data),
		headers: {
			'Content-Type': 'application/json'
		}
	});

	if (!success) {
		// Show a warning that the user might lose data if they leave the page
		event.preventDefault();
		event.returnValue = '';
	}
});

Browser compatability

This library requires, at the minimum, support for XMLHttpRequest, including setRequestHeaders and withCredentials. Those are supported in IE10 and above.

Methodoloy

We first try to use navigator.sendBeacon if it's available and the request is compatible. Compatible requests are POST requests with 'include' as the credentials mode and no headers, with the exception of Content-Type if the data being sent is a string. navigator.sendBeacon can also fail if the data being sent is over the maximum size limit or due to a browser issue with Content-Type.

If navigator.sendBeacon is not available, if the request is not compatible, or if it otherwise fails, we then try to use synchronous XMLHttpRequest. Some browsers disallow synchronous XHR on beforeunload.

If synchronous XHR fails, we try fetch with the keepalive flag set. We do this after synchronous XHR because fetch with keepalive can fail in certain situations due to a browser issue with headers. This failure cannot be intercepted in a synchronous manner, so there is no way to recover with a different method.

This execution order ensures cross-browser compatability with, despite the quirks and issues with the new APIs. That being said, to guarantee the best user experience, you should aim for your requests to be compatible with navigator.sendBeacon. This avoids users having to wait for the synchronous XHR to complete when attempting to navigate away.