Giter Site home page Giter Site logo

backburner.js's Introduction

backburner.js Build Status

A rewrite of the Ember.js run loop as a generic microlibrary.

TL;DR

A priority queue that will efficiently batch, order, reorder and process work; done via scheduling work on specific queues.

API

Constructor

Constructor Description
new Backburner() instantiate a Backburner instance with an array of queue names

Instance methods

Method Description
Backburner#run execute the passed function and flush any deferred actions
Backburner#defer defer the passed function to run inside the specified queue
Backburner#deferOnce defer the passed function to run inside the specified queue, only execute it once
Backburner#setTimeout execute the passed function in a specified amount of time
Backburner#debounce execute the passed function in a specified amount of time, reset timer upon additional calls
Backburner#throttle rate-limit the passed function for a specified amount of time
Backburner#cancel cancel a deferOnce, setTimeout, debounce or throttle
Backburner#on Add an event callback. Supports the following events:
  • begin - Fires whenever the runloop begins. Callbacks are passed the current instance and the previous instance.
  • end - Fires whenever the runloop ends. Callbacks are passed the current instance and the next instance.
Backburner#off Removes an event callback
Backburner#join Join the passed method with an existing queue and execute immediately, if there isn't one use Backburner#run
Backburner#getDebugInfo Returns debug information for counters, timers and queues, which includes surfacing the stack trace information for the respective calls

Alias

Alias Description
Backburner#schedule same as defer
Backburner#scheduleOnce same as deferOnce
Backburner#later same as setTimeout

Example usage

The following code will only cause a single DOM manipulation:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Backburner demo</title>
  </head>

  <body>
    <div id="name"></div>

    <script type="module">
      import Backburner from './dist/es6/backburner.js'

      var backburner = new Backburner(['render']),
        person = {name: 'Erik'};

      function updateName() {
        document.querySelector('#name').innerHTML = person.name;
      }

      function setName(name) {
        person.name = name;
        backburner.deferOnce('render', updateName);
      }

      backburner.run(function() {
        setName('Kris');
        setName('Tom');
        setName('Yehuda');
      });
    </script>
  </body>
</html>

backburner.js's People

Contributors

alias-mac avatar asakusuma avatar bekzod avatar davidtaylorhq avatar ebryn avatar ef4 avatar eoinkelly avatar givanse avatar hjdivad avatar joliss avatar kanongil avatar kingpin2k avatar krisselden avatar ksol avatar lynchbomb avatar machty avatar marcioj avatar mmun avatar pittst3r avatar potomak avatar runspired avatar rwjblue avatar scalvert avatar seanpdoyle avatar stefanpenner avatar teddyzeenny avatar tim-evans avatar tricknotes avatar turbo87 avatar wagenet avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

backburner.js's Issues

Scheduling a short setTimeout followed by a long one, causes the short one to hang until the long one executes

Consider the case where we call setTimeout(0) and then setTimeout(500)
Currently if the setTimeout(500) is called in the same run loop as the first one, it will cause the setTimeout(0) to also wait 500 ms.

This bug was introduced by #94

In particular, https://github.com/ebryn/backburner.js/pull/94/files#diff-820bd966639ebce8fcbffd97fb5dac41R441seems wrong, because if we have an expired timeout that hasn't fired, wait time should be 0.
I am a bit concerned with the computer sleep issue, because now and also with this fix, you could get a timeout from couple days ago which is not how the native browser setTimeout behaves. Maybe we should have a max expired time after which we ignore the timeouted function?

This seems like a probable cause of emberjs/ember.js#10479

Ember.run.later will never execute under some conditions

We are seeing this behavior intermittently:

  • Ember.run.later is called to schedule a future execution
  • Internally, this updates laterTimerExpiresAt to the next future execution timestamp and a browser setTimeout schedules the call and timer id is recored in laterTimer.
  • The computer goes to sleep
  • Computer wakes.
  • Intermittent: the timer never fires.
  • Now, laterTimerExpiresAt and laterTimer hold values that cause this updateLaterTimer to never execute its body, causing future schedule calls to never execute.
function updateLaterTimer(self, executeAt, wait) {
  if (!laterTimer || executeAt < laterTimerExpiresAt) {
    // we don't enter this block because 
    // executeAt > laterTimerExpiresAt and laterTimer has a value.
    ...

    // executeAt could also be in the past after a sleep/wake
    laterTimerExpiresAt = executeAt;
  }
}

Possible fix:

function updateLaterTimer(self, executeAt, wait) {
  var now = (+new Date());
  if (!laterTimer 
      || (executeAt < laterTimerExpiresAt) 
      || (laterTimerExpiresAt < now)) {

    if (laterTimer) {
      // immediately trigger any stale timers.
      if (laterTimerExpiresAt < now) {
        wait = 0;
      }
      clearTimeout(laterTimer);
    }   

    laterTimer = global.setTimeout(function() {
      laterTimer = null;
      laterTimerExpiresAt = null;
      executeTimers(self);
    }, wait);

    // base laterTimerExpiresAt to now and setTimeout wait value
    laterTimerExpiresAt = now + wait;
  }   
} 

deferOnce() is broken

In current master:

During a flush calling deferOnce() using a obj+method that has already executed, it will forget the newly deferred action. I believe this regression is tied to the new guid code.

Refactor away from relying on `this` in module scope.

References to this in root module scope are no longer guaranteed to be window, and some transpilers actively rewrite this to undefined to ensure future compatibility.

Example with Esperanto:

Input (as used here):

var global = this;

Output:

define(function () {

    'use strict';

    var global = undefined;

});

Replacing this with window would work in the standard browser case. Does anyone have an issue with detecting window and using it?

Add benchmarks

Need to figure out a nice way to add benchmarks into the repo

Debouncing is actually throttling

The debounce method currently throttles a function, rather than debouncing it. A true debounce function should call a function if it hasn't been called within the wait time.

Running `Backburner.run.later` periodically end up with huge CPU usage

At TravisCI we had a problem with CPU usage skyrocketing after an hour or two of using the site. Initially I thought that this is a result of the amounts of data we may keep in Ember Data's store, we get a lot of pusher updates with new jobs and builds and it seemed to me that with a lot of those, all the filtering takes up more and more time.

After investigating it more closely it turned out that the code responsible for such a behaviour was Ember.run.later, which was run periodically: travis-ci/travis-web@4288e79

I'm not sure why Ember.run.later was used there in the first place and I'm not sure if this is sane thing to do, but it seems to me that there may be a leak somewhere. I prepared a simple app which increments a counter using Ember.run.later and setTimeout.

After about 2000 runs the CPU usage was respectively ~8% and ~0.2-0.5%. After keeping it open for a longer time it will eventually get near 100% of CPU usage on the Em.run.later version.

Throttle support for calling on leading edge

Currently throttle always calls the given function on the trailing edge of wait period. Adding support to control leading and/or trailing edge calls (as exists in underscore.js) would be very useful.

Use case: throttling scroll updates. On desktop browsers it's useful to throttle scroll handlers. On iOS devices, a single scroll event is only fired at the end of scroll. Using throttle in this case has the effect of simply delaying the scroll handler on iOS. Enabling leading-edge triggering would resolve this.

If this feature is desirable, I'm happy to do the PR.

Queue.pushUnique is slow for large queues

In my ember-data app I initialize about 2000 records at once. This causes about 2 thousand queue entries. Entries are added to the queue using pushUnique. PushUnique uses a for loop to check for existing entries giving O(n^2) performance when adding to the queue. For 2k entries, this is noticeably slow, especially on mobile devices.

pushUnique could use a hash to check uniqueness and it would be a lot faster.

[FEATURE REQUEST] Integrate into ember

I would like to use this in a non framework proof of concept, but before I invest time in learning the source I would like to know if this will eventually be used by ember?

implement `run.join` at the BB level

  • implement backburner.join(..) that ensure a task is run within runloop, or scheduled on some queue
  • implement backburner.joinOn(queue, ...) ensure the task is within a runloop or joins the current runloop on a specific queue

Ember.run.debounce 'immediate' option does not call supplied method immediately

The Ember.run.debounce method advertises that, if supplied a boolean, it would run the method on the leading edge of the wait interval. That means to me, that if I run this function, it should run immediately, but future calls to this will be ignored for the full length of the specified time period, after which, a future call to the debounced function would execute, and so on and so forth. Either I'm not thinking about it right, or something in Ember is broken.

I'm using it like this:

Ember.run.debounce(this, this.validateCategory, 1000, true);

This should run immediately when called, but it does not. Instead, it runs the default behavior, as if 'immediate' was always set to false.

how do I get the simple example to run standalone?

Hi Guys, How do I get backburner to run stand alone?

I built using using ember build and included that file in a script tag on a vanilla .html page like so...

<script src="vendor/backburner/dist/backburner.js"></script>

The browser loads the file and I assumed I would see something like Backburner or maybe BB on the global scope -- but I don't.

What am I doing wrong?

Add a new run loop function to coalesce requests until timer ends

We are needing a new run loop function that works similar to debounce, but functions a little differently.

How it would work is as follows:

  • A call is made to the coalesce function and the method is run immediately. A timer is also started for that method signature.
  • Each additional call cancels the current timer and creates a new one (like debounce). A counter is also incremented for each time the method signature is called.
  • When the timer is complete, if the counter is greater than 0 (meaning the method was called more than once during the timeout period), the method is called a second time.

Our use case is, we have a web socket that pushes data updates to the front end on any backend change. We want the first data update to fire immediately, but then coalesce all the remaining data updates until the timer expires. We find that we are updating the data several times on the backend (with various backend processes), but want to limit the number of requests on the front end until we know the changes are complete.

Debounce and throttle don't meet this requirement. I looked at extending backburner locally, but that would require rewriting and implementing many of the internal functionality to add this new method. It would be much easier to add it in backburner directly.

I'm adding an issue here, to see if I created a pull request, if this is something that you could see being used else where and would be pulled into backburner to make available for ember?

Exception while using the globals s3 version of backburner

When including the latest backburner on a page via:

http://builds.emberjs.com.s3.amazonaws.com/backburner.js/lastest/backburner.js

An exception occurs:

Uncaught Error: Could not find module backburner/deferred_action_queues backburner.js:18
requireModule backburner.js:18
requireModule backburner.js:31

get Name of currently executing queue

Is there a straightforward way to see what queue a job has been scheduled to while the job is running (if, for example, the job contained a debugger statement)? IOW, can a job access the name of the queue it is running in?

Throttle: Support leading and trailing edge?

Right now backburner's throttle (and ultimately Ember.run.throttle) has a mutually exclusive edge. immediate is either true or false resulting in leading or trailing edge invocation respectfully. Other libraries (underscore and lodash) can support both leading and trailing edge invocations.

I was curious if that's something backburner would be open to?

Need hook for when run loop finishes

There should be a generalized hook for a callback whenever the runloop completes. I think what we want is a hook into whenever onEnd fires.

I want this for determining whenever a render might have happened, and @stefanpenner needs this for some RSVP unhandled error handling.

I just want to kick off some discussion before I submit a PR for this.

setTimeout problems on iOS 6

This is actually a browser bug/quirk but seriously affects backburner. If setTimeout is called while a page is scrolling on iOS 6.0, the timeout never fires. Obviously this affects backburner in many ways.

http://jsbin.com/agebuqeP/2 shows this in action. Load this page on a device running iOS 6.0. Pinch-zoom the page. You'll see the big square change color but no alert will appear. Try on a device running iOS 7 and the square will change color and the alert will appear.

Fixing this is non-trivial but there are work-arounds such as this: https://gist.github.com/ronkorving/3755461

I wanted to log this so other people experiencing bizarre behaviour in their backburner/Ember apps have an explanation.

Include License File

The package.json states a BSD license, but this is ambiguous.

Which of the BSD style licenses do we use?

SPDX has a great list of OSS license (along with identifiers to be used) and lists the following BSD licenses:

BSD-2-Clause
BSD-2-Clause-FreeBSD
BSD-2-Clause-NetBSD
BSD-3-Clause
BSD-3-Clause-Clear
BSD-4-Clause
BSD-4-Clause-UC

Of these only BSD-2-Clause and BSD-3-Clause are OSI approved.

We could also use MIT which is also OSI approved. I am unsure if this would require contributor sign-off though.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.