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

bifur

v1.2.2

Published

A library providing simple use of asynchronous functionality via Web Workers.

Downloads

8

Readme

Accessible and understandable multi-threading that doesn’t complicate your codebase.

Not only is Bifur a kick-arse dwarf from The Hobbit. His name literally means to divide into two branches or parts.

Bifur allows you to run code alongside other code so as not to block the main thread (i.e. cause the browser to lock up) when performing heavy operations!

There are two big hurdles when running code in parallel with web workers:

  • Web Workers are fiddly and complicated to set up initially.
  • Knowing when a particular request has returned from a Web Worker can be tricky.

Bifur does the hard work for you and allows you to pass in a function and an array of arguments, and returns you a promise that will resolve when your function is complete!

Table of Contents

Compatibility

Bifur is intended for browser use only and is compatible with all major browsers.

Check for specific browser compatibility here: https://caniuse.com/webworkers

Installation

Use the package manager npm to install Bifur.

npm install bifur

Usage

Firstly, import Bifur into your environment...

If you're using something like React or Vue then import like so:

import Bifur from "bifur";

The library also offers an ES version for more optimised builds:

import Bifur from "bifur/module";

Additionally, you can import directly into HTML files via something like unpkg:

<script type="module">
    import 'https://unpkg.com/bifur';
</script>

From here on you can call Bifur.run which accepts two arguments, a Function and an Array respectively.

Bifur.run(
    (a,b) => {
        return a + b;
    },
    [2,3]
);

The function should be self-contained as it will be run in a completely separate thread to your current code.

The array of arguments should align with the parameters that your function expects.

The run method will then return a Promise that resolves when the function has finished its calculations.

Bifur.run(
    (a,b) => {
        return a + b;
    },
    [2,3]
).then(result => {
    console.log(result); // 5
})

OR

const result = await Bifur.run(
    (a,b) => {
        return a + b;
    },
    [2,3]
);
// result = 5

Documentation

Bifur can be used statically for ease and simplicity.

Bifur currently provides just one method, run.

Methods

run

Bifur.run(func, array);

Runs the provided function asynchronously to the main thread, passing it the arguments supplied via the array provided.

Arguments

[method] (Function): The method to be involved asynchronously to the main thread.

[arguments] (Array): The arguments to pass to the array. Note: this array will be spread to allow the function to have multiple parameters.

Returns

(any): Returns the returned value of the function provided.

Example:

const result = await Bifur.run(
    (a,b) => {
        return a + b;
    },
    [2,3]
);
// result = 5

persist

const persistedThread = Bifur.persist(func);

Creates a persisted worker that performs the supplied function when run. The advantage of this over simply using the run method is that the worker persists and isn't destroyed after one use. This helps performance, but also allows you to persist a state within the thread.

Arguments

[method] (Function): The method to be involved asynchronously to the main thread.

Returns

(any): Returns an instance of PersistedWrapper.

Example 1:

const thread = Bifur.persist(
    (a,b) => {
        return a + b;
    }
);
const result = await thread.run([2,3]);
// result = 5

Example 2 - state persistence:

const thread = Bifur.persist(
    (a,b) => {
        // Create a state in the thread if one doesn't exist already.
        if(!this.state) {
            this.state = 0;
        }
        const result = a + b;
        this.state += result;
        return this.state;
    }
);
const result = await thread.run([2,3]);
// result = 5

const result = await thread.run([2,3]);
// result = 10

Additional Information

Heavier Examples

The following functionality, if run in browser, will lock up the UI for several seconds while computing. Paste it into the browser console to see for yourself.

let fibonacci = (num) => { 
    if (num <= 1) return 1; 
    return fibonacci(num - 1) + fibonacci(num - 2); 
}
console.time('fibonacci');
fibonacci(42);
console.timeEnd('fibonacci');

When running this with Bifur, the UI will continue running as usual while this calculation is made on a separate thread! Implemented like so...

const result = await Bifur.run(
    (num) => {
        let fibonacci = (num) => {
            if (num <= 1) return 1;
            return fibonacci(num - 1) + fibonacci(num - 2);
        }
        return fibonacci(num);
    },
    [42]
);

Now running the same function but using a persisted worker and holding the results in state means we can recall the result of a previously calculated function and respond far more quickly.

const thread = Bifur.persist((num) => {
    // Generate a state if one doesn't exist.    
    if(!this.state) {
        this.state = {};
    }

    // If we've already worked this out and saved it in the state then return the previous result.
    if(!!this.state[num]) {
        return this.state[num];
    }

    let fibonacci = (num) => {
        if (num <= 1) return 1;
        return fibonacci(num - 1) + fibonacci(num - 2);
    }
    const result = fibonacci(num);

    // Persist the result in the thread's state.
    this.state[num] = result;

    return result;
});

await thread.run([42]); // Runs in a few seconds

await thread.run([42]); // Runs in a few milliseconds

Note that pasting this into your browser will not work unless you import Bifur!

Why not just use Promises?

To quote an excellent answer from our beloved StackOverflow:

Deferred/Promises and Web Workers address different needs:

- Deferred/promise are constructs to assign a reference to a result not yet available, and to organize code that runs once the result becomes available or a failure is returned.

- Web Workers perform actual work asynchronously (using operating system threads not processes - so they are relatively light weight).

Source: https://stackoverflow.com/questions/20929508/web-workers-vs-promises#answers-header

Future Improvements

  • Test files could be TypeScript.
  • Worker could be mocked in more detail.
  • Tests could be run in a headless browser environment like Selenium.

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

License

MIT