An open API service indexing awesome lists of open source software.

https://github.com/anonyco/spromisemespeedjs

The JavaScript library that promises you the fastest ES6 promises
https://github.com/anonyco/spromisemespeedjs

bluebird bluebird-promise easy-to-use es6-promise javascript javascript-library js polyfill promise promise-api promise-chain promise-library promise-queue promiserejectionevent promises promises-aplus promisify vanilla-javascript vanilla-js vanillajs

Last synced: about 1 month ago
JSON representation

The JavaScript library that promises you the fastest ES6 promises

Awesome Lists containing this project

README

        

[![npm version](http://img.shields.io/npm/v/spromisemespeed.svg?label=version)](https://npmjs.org/package/spromisemespeed "View this project on npm")
[![GitHub stars](https://img.shields.io/github/stars/anonyco/SPromiseMeSpeedJS.svg?style=social)](https://github.com/anonyco/SPromiseMeSpeedJS/stargazers "View others who have stared this repository")
[![GitHub file size in bytes](https://img.shields.io/github/size/anonyco/SPromiseMeSpeedJS/dist/SPromiseMeSpeed.min.js.svg?label=without%20gzip)](https://github.com/anonyco/SPromiseMeSpeedJS/blob/master/dist/SPromiseMeSpeed.min.js "File without gzip")
[![GitHub file size in bytes](https://img.shields.io/github/size/anonyco/SPromiseMeSpeedJS/dist/SPromiseMeSpeed.min.js.gz.svg?label=gzip%20applied)](https://github.com/anonyco/SPromiseMeSpeedJS/blob/master/dist/SPromiseMeSpeed.min.js.gz "Gzipped file")
[![npm bundle size (version)](https://img.shields.io/bundlephobia/min/spromisemespeed/latest.svg?color=maroon&label=NPM%20bundle%20size)](https://npmjs.org/package/spromisemespeed "View this project on npm")
[![CC0 license](https://licensebuttons.net/p/zero/1.0/88x31.png)](https://creativecommons.org/share-your-work/public-domain/cc0/ "This project's liscence")
[![npm downloads](https://img.shields.io/npm/dt/spromisemespeed.svg)](https://npmjs.org/package/spromisemespeed "View this project on npm")

# SPromiseMeSpeed
SPromiseMeSpeed is currently the fastest [ES6 Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) javascript library and polyfill, *promising* a speedy implementation that is ~1-59x faster than Chrome's native promises and ~2-548x faster than Bluebird's promises (five hundread and fourty eight is not a typo). The purpose of SPromiseMeSpeed is to provide a speedy alternative to ES6 promises until browsers implement faster native promises. If all you need is a way to defer the stack level so you don't get the dreaded "Maximum Stack Call Exceeded" error, then consider using my other library, [DeferStackJS](https://github.com/anonyco/DeferStackJS/), for slightly better performance.

# Quick Start

To use, simply drop the following snippet of HTML code into your `` before all of the scripts that use SPromiseMeSpeed.
```HTML

```
Or, alternatively, if you want faster page loading, add a defer to every script to let the browser know that you don't call evil `document.write` inside your script.


*Before:*
```HTML

...

```
*After*
```HTML

...

```

## RequireJS and NodeJS Setup

For dropping into either RequireJS or NodeJS, please use [the `spromisemespeed` npm repository](https://npmjs.org/package/spromisemespeed), [this minified file](https://github.com/anonyco/SPromiseMeSpeed/blob/master/dist/SPromiseMeSpeed.min.js), or the corresponding [source code file](https://github.com/anonyco/SPromiseMeSpeed/blob/master/src/SPromiseMeSpeed.src.js). To install via npm, use the following code.

```Bash
npm install spromisemespeed
```

After installing via npm, one can use `require("spromisemespeed")`. Alternatively, one can drop the *SPromiseMeSpeed.min.js* file into the same directory as their NodeJS script and do `require("./SPromiseMeSpeed.min.js")`. Both methods are functionally equivalent. Otherwise, if one do not know how to use the command line, save the script corresponding to one's operating system to the directory where the nodejs script will run and use the file manager to run the script (on Windows, it's a double-click).

* fastestsmallesttextencoderdecoder
- Microsoft Windows batch: [install-FastestSmallestTextEncoderDecoder-windows.bat](https://raw.githubusercontent.com/anonyco/SPromiseMeSpeedJS/master/dist/install-SPromiseMeSpeed-windows.bat)
- Bash for Apple MacOS and Linux (e.x. Ubuntu): [install-FastestSmallestTextEncoderDecoder-unix.sh](https://raw.githubusercontent.com/anonyco/SPromiseMeSpeedJS/master/dist/install-SPromiseMeSpeed-unix.sh)
* fastestsmallesttextencoderdecoder-encodeinto
- Microsoft Windows batch: [install-FastestSmallestTextEncoderDecoder-encodeInto.bat](https://raw.githubusercontent.com/anonyco/SPromiseMeSpeedJS/master/dist/dist/install-SPromiseMeSpeed-fast.bat)
- Bash for Apple MacOS and Linux (e.x. Ubuntu): [install-FastestSmallestTextEncoderDecoder-encodeInto.sh](https://raw.githubusercontent.com/anonyco/SPromiseMeSpeedJS/master/dist/dist/install-SPromiseMeSpeed-fast.sh)

# API: Differences From Native Promises
SPromiseMeSpeed gives you one and only one new global on the window object: `window.SPromise`. `window.SPromise` is the exact same as the native `window.Promise` as documented by MDN EXCEPT:

1. It is called without the `new` operator.
1. All callbacks are invoked immediately after the promise is resolved without waiting until the next tick.
1. It has a `window.SPromise.isPromise` method you can use to determine if something is a promise.
1. It is a lot faster than native Chromium promises, even with (surprise, surprise!) `await`.
1. It skims and cuts corners to boost performance by reusing the same reference passed to callbacks as the source.

Example code snippets:
```HTML

SPromise Test Example

addEventListener("load", function(){
"use strict";
var SPromise = window.SPromise;
SPromise.race([
SPromise(function(accept){
setTimeout(function(){
accept("SPromise wins this mockup that doesn't actually have any benchmarking practicality");
}, 250);
}),
new Promise(function(accept){ // you can even intermingle native promises with SPromise
setTimeout(function(accept){
accept("Native Promise wins this mockup that doesn't actually have any benchmarking practicality")
}, 250)
})
]).then(function(winner){
document.body.insertAdjacentHTML("beforeend", "<div>Winner:" + winner + "</div>");
});
(async function(){
document.body.insertAdjacentHTML("beforeend", "<div>" + await SPromise(function(accept, reject){
// Don't ask me why synthetic promises are allowed to work with await. I myself am still
// confused, but hey: it works and SPromise even somehow shockingly makes them faster!
setTimeout(function(){
accept("Hello from await!")
}, 750);
}) + "</div>");
})();
})();

```

# SPromiseMeSpeed.min.js VS SPromiseMeSpeedDEBUG.min.js
The main difference between the two versions is that SPromiseMeSpeedDEBUG is intended for development. It adds many extra type checks and notifies you when the wrong type of object is passed to the SPromise API. For some of the errors, it even gives a suggestion on how to fix them. However, these checks come at a cost: performance. If you have already written your code well enough to not need these checks, then use SPromiseMeSpeed.min.js for even better performance. SPromiseMeSpeed.js will run blind untill it gets done running or it hits a wall and crashes. For example, if you pass something that is not a function to `window.SPromise` from SPromiseMeSpeedDEBUG.min.js, then it will print a pretty error message saying you passed a wrong type to the function. But with SPromiseMeSpeed.min.js, the console will say something along the lines of 'cannot call null or undefined' or 'null or undefined is not a function.' To use SPromiseMeSpeed without the DEBUG, insert the following alternative code into your ``:

```HTML

```

## RequireJS and ES Module API Documentation

For NodeJS, calling `require("SPromiseMeSpeed.min.js")` yields the function `SPromise`.

```Javascript
module.exports = function(handle) {/*...*/};
```

As for example snippets, observe the way to require modules below.

```Javascript
const SPromise = require("spromisemespeed");
```

Or, one can use the new and shiny [ES6 module importation](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/import) statements.

```Javascript
// Variation 1
import { SPromise } from "spromisemespeed";
```

```Javascript
// Variation 2
import * as SPromiseModule from "spromisemespeed";
const SPromise = SPromiseModule.SPromise;
```

## npm Project
This DEBUG build of this project can be found on [npm here at this link](https://npmjs.org/package/spromisemespeed). The faster unchecked build can be found on [npm here at this other link](https://npmjs.org/package/spromisemespeed-fast).

# Benchmarks
If you are a sensible guy like me, then you shouldn't take my word for the speed of SPromiseMeSpeed. Rather, take the word of these benchmarks:

### Casual Promising
Benchmark Code (executed in the console at https://cdnjs.cloudflare.com/ajax/libs/bluebird/2.11.0/bluebird.min.js)
```Javascript
(async function(requestIdleCallback, console, performance){
"use strict";
var resStr = "";
var nativePromise = window.Promise, idleOptions = {timeout: 11};
function test(str, f){
return new nativePromise(function(acc){
var tests=[], tmp=0, SPromise = window.SPromise;
var cycleCount=5, intV=requestIdleCallback(function theeFunc(){
"use strict";
if (--cycleCount < 0) {
var res = tests.reduce((a, b) => a + b) / tests.length;
resStr += "\n" + str + res + "ms";
acc();
return;
}
var k = performance.now(), i = 0, Len = 6;
(function test(v){
f(function(k){
k(v+(((v<<2)%11)|0)|0);
}).then(function(v){
i = i + 1|0;
if (i < Len) {
test(((v|0)%7)|0);
} else {
tmp = tmp + (v|0)|0;
tests.push((performance.now() - k)/Len);
}
});
})(Math.random()*40|0);
requestIdleCallback(theeFunc, idleOptions);
}, idleOptions);
});
}

await test("NativeR1: ", function(x){return new nativePromise(x)});
await test("NativeR2: ", function(x){return new nativePromise(x)});
await test("NativeR3: ", function(x){return new nativePromise(x)});
await test("NativeR4: ", function(x){return new nativePromise(x)});
await (new nativePromise(_=>requestIdleCallback(_))); // to allow the CPU to take a break
(new Function(document.body.innerText))();
var bbPromise = window.Promise;
await test("BluebirdR1: ", function(x){return new bbPromise(x)});
await test("BluebirdR2: ", function(x){return new bbPromise(x)});
await test("BluebirdR3: ", function(x){return new bbPromise(x)});
await test("BluebirdR4: ", function(x){return new bbPromise(x)});
await (new nativePromise(_=>requestIdleCallback(_))); // to allow the CPU to take a break
window.Promise = nativePromise;
var SPromise = window.SPromise;
await test("SPromiseR1: ", function(x){return SPromise(x)});
await test("SPromiseR2: ", function(x){return SPromise(x)});
await test("SPromiseR3: ", function(x){return SPromise(x)});
await test("SPromiseR4: ", function(x){return SPromise(x)});
console.log(resStr);
})(requestIdleCallback, console, performance);
```
Console output (lower numbers = lower promise delay = better):
```
NativeR1: 0.04416666730927924ms
NativeR2: 0.018666667165234685ms
NativeR3: 0.026166668006529413ms
NativeR4: 0.024499996410061918ms
BluebirdR1: 0.27599999836335576ms
BluebirdR2: 0.22883333343391615ms
BluebirdR3: 0.22850000144292912ms
BluebirdR4: 0.2271666657179594ms
SPromiseR1: 0.006999998974303404ms
SPromiseR2: 0.006166667056580384ms
SPromiseR3: 0.005999997180576125ms
SPromiseR4: 0.006833329098299146ms
```

### Synchronous Hellhole of Death Promising
Benchmark code (executed in the console at https://cdnjs.cloudflare.com/ajax/libs/bluebird/2.11.0/bluebird.min.js):
```Javascirpt
(async function(requestIdleCallback, console, performance){
"use strict";
var resStr = "";
var nativePromise = window.Promise, idleOptions = {timeout: 11};
function test(str, f){
return new nativePromise(function(acc){
var tests=[], tmp=0, SPromise = window.SPromise;
var cycleCount=5, intV=requestIdleCallback(function theeFunc(){
"use strict";
if (--cycleCount < 0) {
var res = tests.reduce((a, b) => a + b) / tests.length;
resStr += "\n" + str + res + "ms";
acc();
return;
}
var i = 0, k = performance.now();
(function test(v){
f(function(k){
k(v+(((v<<5)%11)|0)|0);
}).then(function(v){
i = i + 1|0;
if (i < 131072) {
test(v%7|0);
} else {
tests.push((performance.now() - k)/131072);
tmp = tmp + v|0;
clearInterval(intervalID);
requestIdleCallback(theeFunc);
}
});
})(Math.random()*40|0);
var last = 0;
var intervalID = setInterval(function(){
if (last !== i) {last = i; return}
i = 131072;
clearInterval(intervalID);
tests.push((performance.now() - k)/i);
requestIdleCallback(theeFunc);
}, 10);
}, idleOptions);
});
}

await test("NativeR1: ", function(x){return new nativePromise(x)});
await test("NativeR2: ", function(x){return new nativePromise(x)});
await test("NativeR3: ", function(x){return new nativePromise(x)});
await test("NativeR4: ", function(x){return new nativePromise(x)});
await (new nativePromise(_=>requestIdleCallback(_))); // to allow the CPU to take a break
(new Function(document.body.innerText))();
var bbPromise = window.Promise;
await test("BluebirdR1: ", function(x){return new bbPromise(x)});
await test("BluebirdR2: ", function(x){return new bbPromise(x)});
await test("BluebirdR3: ", function(x){return new bbPromise(x)});
await test("BluebirdR4: ", function(x){return new bbPromise(x)});
await (new nativePromise(_=>requestIdleCallback(_))); // to allow the CPU to take a break
window.Promise = nativePromise;
var SPromise = window.SPromise;
await test("SPromiseR1: ", function(x){return SPromise(x)});
await test("SPromiseR2: ", function(x){return SPromise(x)});
await test("SPromiseR3: ", function(x){return SPromise(x)});
await test("SPromiseR4: ", function(x){return SPromise(x)});
console.log(resStr);
})(requestIdleCallback, console, performance);
```
Console output (lower numbers = lower promise delay = better):
```
NativeR1: 0.005961311340207942ms
NativeR2: 0.005754425048820622ms
NativeR3: 0.005737731933574963ms
NativeR4: 0.005725685119539747ms
BluebirdR1: 0.0004817428588488326ms
BluebirdR2: 0.0003913345338446561ms
BluebirdR3: 0.0003724441526742339ms
BluebirdR4: 0.00038145446783488524ms
SPromiseR1: 0.0002370834351062001ms
SPromiseR2: 0.00017644500722724388ms
SPromiseR3: 0.00017766571041022416ms
SPromiseR4: 0.00017798614484476616ms
```

### Await Promising
Benchmark Code (executed in the console at https://cdnjs.cloudflare.com/ajax/libs/bluebird/2.11.0/bluebird.min.js):
```Javascript
(async function(performance, console){
"use strict";
var resStr="";
var nativePromise = window.Promise, idleOptions = {timeout: 10};
function acceptor(acc){acc();}
function test(str, f){
return new nativePromise(function(acc){
var tests=[], SPromise = window.SPromise;
var cycleCount=6, intV=requestIdleCallback(function theeFunc(){
"use strict";
if (--cycleCount < 0) {
var res = tests.reduce((a, b) => a + b) / tests.length;
resStr += "\n" + str + res + "ms";
acc();
return;
}
var k = performance.now(), i = 0;
(async function test(){
await f(acceptor);
if (i < 384) {
i = i+1|0;
test();
} else {
tests.push((performance.now() - k)/384);
requestIdleCallback(theeFunc, idleOptions);
}
})(Math.random()*40|0);
}, idleOptions);
});
}

await test("NativeR1: ", function(x){return new nativePromise(x)});
await test("NativeR2: ", function(x){return new nativePromise(x)});
await test("NativeR3: ", function(x){return new nativePromise(x)});
await (new nativePromise(_=>requestIdleCallback(_))); // to allow the CPU to take a break
(new Function(document.body.innerText))();
var bbPromise = window.Promise;
await test("BluebirdR1: ", function(x){return new bbPromise(x)});
await test("BluebirdR2: ", function(x){return new bbPromise(x)});
await test("BluebirdR3: ", function(x){return new bbPromise(x)});
await (new nativePromise(_=>requestIdleCallback(_))); // to allow the CPU to take a break
window.Promise = nativePromise;
var SPromise = window.SPromise;
await test("SPromiseR1: ", function(x){return SPromise(x)});
await test("SPromiseR2: ", function(x){return SPromise(x)});
await test("SPromiseR3: ", function(x){return SPromise(x)});
console.log(resStr);
})(performance, console);
```
Console output (lower numbers = lower promise delay = better):
```
NativeR1: 0.008009982618912342ms
NativeR2: 0.010225694394547543ms
NativeR3: 0.01835503472749325ms
BluebirdR1: 4.231184895818134ms
BluebirdR2: 4.206684027773615ms
BluebirdR3: 4.192039930558167ms
SPromiseR1: 0.016039496535490295ms
SPromiseR2: 0.010410156290971728ms
SPromiseR3: 0.010818142375986403ms
```
[Caution: Please don't read the following paragraph if you are easily disturbed by vivid images of emesis. Also, note that this paragraph has been a bit less applicable since Chrome's `await` recieved internal optimizations.] The significance of the above tests is that trying to force a native method like `await` into using a user-created function like `SPromise` is comparable to trying to swallow someone else's barf. If you are going to swallow barf (as in `await`), you would likely want to swallow your own *native* barf instead of trying to swallow the barf of someone else (like Bluebird or SPromise). Yet in spite of this, SPromise makes the barf tasty (fast and performant) enough for Chrome to swallow it with greater efficiency.

## Development

On Linux, the project can be developed by cloning it with the following command line.

```Bash
git clone https://github.com/anonyco/SPromiseMeSpeedJS.git; cd SPromiseMeSpeedJS; npm run install-dev
```

Emphasize the `npm run install-dev` which downloads `closure-compiler.jar` into the repository for minifying the files.

Now that the repository is cloned, edit the files as one see fit. Now that the files have been edited, run the following in the terminal in the root folder of the repository in order to minify the NodeJS JavaScript files.

```Bash
npm run build
```

## Continuity

Feel free to reach out to me at [email protected]. I am fairly attentive to my GitHub account, but in the unlikely event that issues/pulls start piling up, I of course welcome others to step in and contribute. I am widely open to input and collaboration from anyone on all of my projects.