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

async-priority-queue

v0.1.2

Published

A package to simplify queueing and control of asynchronous tasks

Downloads

467

Readme

#Async Priority Queue

AsyncPriorityQueue is an abstraction designed to simplify queueing and coordinating the control flow of asynchronous tasks. The initial use case was for prioritizing network requests in a single page app. More specifically, suppose you have an app with many UI components, each independently polling a backend server for new data or making mutative requests in response to user interaction. Most browsers limit the number of concurrent AJAX requests (for Chrome, this number is 6). Therefore, it is easy to envision a scenario where a large number of potentially slow, low priority GET requests are preventing an important PUT or POST request from starting. With AsyncPriorityQueue, you get single shared queue that all network requests flow through, and individual requests (or classes of requests) can execute with different priorities.

Installation

Install with npm:

npm install async-priority-queue

Then require the AsyncPriorityQueue and AsyncTask constructors in your code:

var AsyncPriorityQueue = require('async-priority-queue').AsyncPriorityQueue;
var AsyncTask = require('async-priority-queue').AsyncTask;

// or with ES6
const {AsyncPriorityQueue, AsyncTask} = require('async-priority-queue');

Usage

Suppose you have the following UI code (I use a React component, but any view framework would suffice):

var MyComponent = React.createClass({
  componentDidMount: function() {
    var self = this;
    setInterval(function() {
      self.setState({data: $.get('example.com/data/' + self.props.id)});
    }, 5000);
  },
  render: function() {
    return <button onClick={$.post('example.com/data/' + this.props.id, {data: {name: Math.random()}})}/>
  }
};

If there are many instances of MyComponent on the page, many concurrent GET requests could be active at any time. If more than 6 are in flight at a time, additional requests are queued up by the browser, with no way to prioritize or cancel existing requests. So if a user clicks the button, it may be a long time before the POST request gets to the server, and the user is stuck in an unclear state. This is problem can be solved using an AsyncPriorityQueue:

// First, instantiate a queue:
var queue = new AsyncPriorityQueue();

// Now, whenever a component needs to make a request, instantiate an AsyncTask to encapsulate it:

var task = new AsyncTask({
  priority: 'high', 
  callback: function() {
    return $ajax.post('example.com/data/' + self.props.id, {data: {name: 'name' + Math.random()}});
  }
});

// tasks expose a promise in case you need to execute code when the request finishes (for showing/hiding a spinner, perhaps).

self.setState({loading: true});
task.promise.then(function() { self.setState({loading: false}); })

queue.enqueue(task);

The enqueued task is not executed right away. Instead, it is placed in one of three queues based on its priority ('low', 'mid', or 'high'). Every 30ms, these queues are inspected (timing is configurable, see API section). If fewer than 6 tasks are currently in flight (also configurable), a new task is chosen, starting from the high priority queue. If it's empty, the mid priority queue is checked, otherwise a low priority task is executed. When a task's callback function is completed, its promise is resolved with the result.

API

###AsyncPriorityQueue

new AsyncPriorityQueue(options = {})

The constructor can take a configuration object that may contain any of the following keys:

debug enables logging statements to help provide visibility into the state of your queue. Defaults to false.

maxParallel is the number of requests that are allowed to be active at a time. Defaults to 6.

processingFrequency is the period in milliseconds between when the queues are checked for new tasks. Defaults to 30.

start()

Starts the processing loop for the queue; tasks can be added and executed.

stop()

Stops the processing loop for the queue; tasks can be added but will not be executed until the queue is started again.

clear(priority)

Clears the queue for a particular priority ('low', 'mid', or 'high'). Useful for when your UI is changing to an unrelated view and you want to cancel all low priority tasks you have queued up (i.e. GET requests for the old UI that are no longer relevant).

enqueue(task)

Takes an AsyncTask and adds it to the correct queue.

processQueue()

This function gets called once every processingFrequency milliseconds. It inspects the state of the queues and the active tasks and executes a new task if necessary. It can be called manually if desired.

###AsyncTask

new AsyncTask(options = {})

The constructor can take a configuration object that may contain any of the following keys:

priority is the relative priority of this task compared to other tasks in the queue. Valid values are low, mid, and high; defaults to mid.

callback is the function to be called when the task is executed. callback must be specified and must return a promise.

promise

An instance of an AsyncTask has a property called promise. This is a promise that is resolved (or rejected) when the callback is finished executing.