Giter Site home page Giter Site logo

ember-app-scheduler / ember-app-scheduler Goto Github PK

View Code? Open in Web Editor NEW
70.0 4.0 24.0 11.48 MB

An Ember addon to schedule work until after the initial render.

Home Page: https://ember-app-scheduler.github.io/ember-app-scheduler/

License: MIT License

JavaScript 69.33% HTML 6.18% CSS 0.15% TypeScript 14.61% Handlebars 9.49% Shell 0.24%
ember addon macro-task paint-phases

ember-app-scheduler's Introduction

ember-app-scheduler

CI Build Ember Observer Score npm version Monthly Downloads from NPM Code Style: prettier

Ember batches DOM updates and paints them after every run loop to prevent layout thrashing. Layout thrashing can prevent a faster First Meaningful Paint (FMP) because all the content of the page is painted at once.

As a way to mitigate the need to render all content at once regardless of its visual priority, some work done on the page like ads, analytics tracking, rendering non critical content, rendering content outside viewport etc. can be deferred to achieve a faster FMP. This work can be delayed to run after the FMP and achieve incremental rendering of the page.

This addon provides a way to defer work into different paint phases of the rendering process to get a faster FMP. It also helps to prioritize and coordinate when the paint happens for different parts of the page.

The documentation website contains more examples and API information.

Compatibility

  • Ember.js v3.16 or above
  • Ember CLI v2.13 or above
  • Node.js v12 or above

Installation

ember install ember-app-scheduler

Usage

The ember-app-scheduler addon connects its functionality via the application's router. By connecting to the router's routeWillChange/routeDidChange hooks (willTransition/didTransition in Ember < 3.6), it ensures that the timing of its API is in sync with the application's timings.

To connect to your router, import setupRouter and reset from ember-app-scheduler and invoke them:

import EmberRouter from '@ember/routing/router';
import { inject as service } from '@ember/service';
import { setupRouter, reset } from 'ember-app-scheduler';
import config from './config/environment';

export default class Router extends EmberRouter {
  location = config.locationType;
  rootURL = config.rootURL;

  @service router;

  constructor() {
    super(...arguments);

    setupRouter(this.router);
  }
}

Router.map(function() {
  // ...
});

Note: There is a bug in Ember.js < 3.26 which may result in Uncaught RangeError: Maximum call stack size exceeded and you may need to use setupRouter(this) instead and deal with deprecation message until you are able to upgrade to 3.26. For more info see emberjs/ember.js#17791

You can then use one of the provided APIs to defer work.

whenRouteIdle

By deferring work until the route is idle (approximately after the first paint completes), we delay non-critical work. To do this, you can import and use the whenRouteIdle function. This is useful for scenarios like rendering ads, scheduling tracking work, rendering of popup overlays etc.

In most cases, the whenRouteIdle function is all you need to defer work, though ember-app-scheduler does expose other functions.

import Route from '@ember/routing/route';
import { whenRouteIdle } from 'ember-app-scheduler';

export default class IdleRoute extends Route {
  activate() {
    super.activate(...arguments);

    whenRouteIdle().then(() => {
      // do non-critical work
    });
  }
}

Contributing

See the Contributing guide for details.

ember-app-scheduler's People

Contributors

bertdeblock avatar brendenpalmer avatar buschtoens avatar chriskrycho avatar dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar ember-tomster avatar nickeidler avatar nlfurniss avatar patrickberkeley avatar rondale-sc avatar rtablada avatar runspired avatar rwjblue avatar sapryniukt avatar scalvert avatar sergeastapov avatar sreedhar7 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

Watchers

 avatar  avatar  avatar  avatar

ember-app-scheduler's Issues

Release 0.1.0 version?

There are a few reasons for this bump:

  • It allows consumers to depend on ember-app-scheduler via ^ (caret) dependency. Which means they can automatically get patch version bumps if we have bugs that need fixing.
  • It signifies that a breaking change has occurred (talking about dropping support for Node < 4 in my last PR).

Any objections?

ChainAlert: npm package release (7.0.1) has no matching tag in this repo

Dear ember-app-scheduler maintainers,
Thank you for your contribution to the open-source community.

This issue was automatically created to inform you a new version (7.0.1) of ember-app-scheduler was published without a matching tag in this repo.

Our service monitors the open-source ecosystem and informs popular packages' owners in case of potentially harmful activity.
If you find this behavior legitimate, kindly close and ignore this issue. Read more

badge

Erroneous deprecation warning?

Hi there,

I think there might be an issue with a deprecation warning recently added here:
https://github.com/ember-app-scheduler/ember-app-scheduler/blob/master/addon/scheduler.ts#L84

The second parameter of deprecate() is documented as follow:

If falsy, the deprecation will be displayed.

Therefore, I wonder if router instanceof Router should instead be !(router instanceof Router) or router instanceof RouterService.

When looking at the code in my debugger console, the code looks like this:

(true && !(router instanceof Ember.Router) && Ember.deprecate('The use of Ember.Router in setupRouter is deprecated. Please use the router service.', router instanceof Ember.Router, {
  id: 'ember-app-scheduler.setupRouter',
  until: '6.0.0'
}));

Related issue: DockYard/ember-router-scroll#271

I am not familiar with Ember deprecations, so apologies if I am mistaken :)

Race condition in acceptance tests for Ember.js 2.15

I was encountering the same issue as DockYard/ember-router-scroll#72. I think the error lies in this addon rather than ember-router-scroll.

  1. The origin is https://github.com/dollarshaveclub/ember-router-scroll/blob/2d577cd4a695310e02db1217d9f8eff5f9bdf1d1/addon/index.js#L25, which explains why it happens only in acceptance tests as route transitions normally do not occur during unit and component integration tests.
  2. The error happens at random times during the execution of acceptance tests which seems to suggest that it's a race condition (the most fun ones :/).

Armed with a debugger and enough patience for the bug to happen, I now have a hypothesis for what is going on. The logic inside the scheduler service is quite complex so I might be wrong. I'll need to test with a fix on my test suite to get confidence that it indeed is the problem.

  1. The error happens on https://github.com/sreedhar7/ember-app-scheduler/blob/master/addon/services/scheduler.js#L71. this.queues is null so the access this.queues[queueName] is the thing that is throwing the error. From the state I could see that the isDestroyed property on the service was true. This means that the willDestroy callback has run, which indeed sets this.queues to null.
  2. The call to flushQueue comes from https://github.com/sreedhar7/ember-app-scheduler/blob/master/addon/services/scheduler.js#L145.

Now is the question, how come the line at https://github.com/sreedhar7/ember-app-scheduler/blob/master/addon/services/scheduler.js#L145 was executed in the first place? Since the service was destroyed, the rAF callback should have been cancelled (from https://github.com/sreedhar7/ember-app-scheduler/blob/master/addon/services/scheduler.js#L163).

I think the only possible explanation is that the following order of execution happens:

  1. The last requestAnimationFrame callback is executed (on https://github.com/sreedhar7/ember-app-scheduler/blob/master/addon/services/scheduler.js#L114).
  2. The service is destroyed.
  3. https://github.com/sreedhar7/ember-app-scheduler/blob/master/addon/services/scheduler.js#L145 is executed via https://github.com/sreedhar7/ember-app-scheduler/blob/master/addon/services/scheduler.js#L128.

The rAF callback is executed in a run.later. I'm thinking that between those two moments, the service is destroyed. Therefore, this.queues is null by the time the callback is called.

It's kind of hard to explain but my fix proposal is to add a guard as follows:

_rAFCallback(resolve) {
  this._nextPaintTimeout = run.later(() => {
    if (!this.isDestroyed) {
      this._nextAfterPaintPromise = null;
      this._nextPaintFrame = null;
      this._nextPaintTimeout = null;
      resolve();
    }
  }, 0)
},

The reason being, I think that the service is destroyed between the scheduling of the callback through run.later and its execution.

Like I said, I still have to test on a fork to see if my explanation is correct and actually fixes the issue. But I thought I'd throw it out here to see if someone had any comments or ideas.

Also, I have no idea why this happens only on Ember.js 2.15.

Could not find module ember-test-waiters imported from ember-app-scheduler/scheduler

Ran in to this (again?):

image

"Error
    at Backburner.scheduleOnce (https://localhost:4201/assets/vendor.js:57443:32)
    at once (https://localhost:4201/assets/vendor.js:41440:23)
    at App.advanceReadiness (https://localhost:4201/assets/vendor.js:35169:27)
    at App._bootSync (https://localhost:4201/assets/vendor.js:35230:14)
    at App.domReady (https://localhost:4201/assets/vendor.js:35120:12)
    at invoke (https://localhost:4201/assets/vendor.js:56976:16)
    at Queue.flush (https://localhost:4201/assets/vendor.js:56867:13)
    at DeferredActionQueues.flush (https://localhost:4201/assets/vendor.js:57064:21)
    at Backburner._end (https://localhost:4201/assets/vendor.js:57598:34)
    at Backburner._boundAutorunEnd (https://localhost:4201/assets/vendor.js:57267:14)"

that probs isn't that helpful,
but, where is the ember-app-scheduler dep specified?

My app has [email protected], which looks like the latest :-\ (since that release there have only been 4 or so pages of dependabot updates ;) )

route-idle helper does not recompute when route is no longer idle

The route-idle helper is super useful for many use cases of when-route-idle. However, I've found that when using the helper in route templates it never recomputes. On initial entry to the route it will work properly, but if the route is re-entered later (e.g. loading a different model), it will immediately return true.

This can lead to (IMHO) unexpected behavior, since I would expect the helper to recompute when the route is no longer idle.

Use RouterService instead of the main Router

Looking at the code for setupRouter(router), it looks like we could also just use the RouterService in newer apps, as it also supports the routeWillChange & routeDidChange events by now.

/**
* Correct connects the router's transition events to
* app scheduler's work.
*
* @param {Router} router An instance of an Ember router.
*/
export function setupRouter(router: Router): void {
if (IS_FASTBOOT || (router as any)[APP_SCHEDULER_HAS_SETUP]) {
return;
}
(router as any)[APP_SCHEDULER_HAS_SETUP] = true;
if (gte('3.6.0')) {
router.on('routeWillChange', beginTransition);
router.on('routeDidChange', endTransition);
} else {
router.on('willTransition', beginTransition);
router.on('didTransition', endTransition);
}
}

I think this would be a bit cleaner, as directly hooking into the main Router feels slightly off to me. It would also allow us to set this up automatically via an instance initializer, in case this is something we'd want.

I'm curious what you think. ๐Ÿ™‚

Currently released package not merged into master branch

I was confused for a while because the currently released version (1.0.4) is not merged to master. I found it on the ts-conversion branch.

If ts-conversion is really supposed to be the default branch, you can set that in github settings.

Convert to v2 addon

As this addon provides only run-time functionality hence it's the great candidate for v2 addon conversion.
There is guide great Porting an Addon to V2 guide I suggest we follow.

My thought process of the next steps is to have PRs in the following order:

  1. convert to monorepo
  2. convert addon to v2
  3. release new major 8.0.0

@scalvert do you have any thoughts, concerns? I can volunteer to work on those

Calling registerWaiter in a production-like environment causes fatal error.

We recently experienced an outage caused by the following code executing in our production environment. We're running Ember 2.18.

We've adjusted our staging build to replicate the error, but it's not clear to me why DEBUG is resolving to true at this line:

I'd really appreciate some guidance on how that is getting set so we can fix our configuration accordingly. Thanks in advance.

screen shot 2018-07-02 at 11 15 36 am

screen shot 2018-07-02 at 11 15 17 am

Embroider warning

I get this warning when building my app. Since the helper is a class-based helper, I'm not sure if this is false flag from Embroider or not. The helper export seems ok to me:

https://github.com/ember-app-scheduler/ember-app-scheduler/blob/master/addon/helpers/route-idle.js

WARNING in ./helpers/route-idle.js 1:0-92
export 'routeIdle' (reexported as 'routeIdle') was not found in '../node_modules/ember-app-scheduler/helpers/route-idle' (possible exports: default)
 @ ./assets/my-app.js 1058:13-48

Seeing race conditions in tests due to waiter

We are seeing our tests randomly failing after using ember-app-scheduler for one of our tests. The error message is: TypeError: Cannot read property 'afterContentPaint' of null.

After looking into the stack trace, it seems to be occurring at this line: https://github.com/sreedhar7/ember-app-scheduler/blob/master/addon/services/scheduler.js#L71 where this.queues is null. In testing mode it seems, this.queues can be null per the check here: https://github.com/sreedhar7/ember-app-scheduler/blob/master/addon/services/scheduler.js#L185

It seems in willDestroy we releasing this.queues itself.

Shouldn't the init here initialize the queues?

Is there a better way to fix this issue? Or is it something wrong with our tests or usage?

cc: @scalvert

Garbage files in npm package

I've installed ember-app-scheduler v0.2.1 and it seems that there are some unneeded files and folders in the package

.node_modules.ember-try/
package.json.ember-try
yarn.lock

v0 2 1

Suggest a different approach to `setupRouter` due to infinite recursion with accessing router service in EmberRouter.init

Problem

Accessing this.router in EmberRouter.init will infinitely recurse due to the issue below.

emberjs/ember.js#17791

export default class Router extends EmberRouter {
  location = config.locationType;
  rootURL = config.rootURL;

  constructor() {
    super(...arguments);

    setupRouter(this.router);
  },

  destroy() {
    reset();

    super.destroy(...arguments);
  }
}

I'm looking to fix this on Friday. So perhaps this doesn't necessarily need to be fixed. Thought I would create an issue for a paper trail.

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.