Coder Social home page Coder Social logo

googlechromelabs / idlize Goto Github PK

View Code? Open in Web Editor NEW
1.0K 24.0 43.0 106 KB

Helper classes and methods for implementing the idle-until-urgent pattern

Home Page: https://philipwalton.com/articles/idle-until-urgent/

License: Apache License 2.0

JavaScript 94.59% HTML 5.41%

idlize's Introduction

Idlize

Helper classes and methods make it easier for developers to implement the idle-until-urgent pattern and leverage the requestIdleCallback() API.

Installation

You can install this library from npm by running:

npm install idlize

Usage

This library is a collection of helper methods and classes (not a single bundle). As such, each helper should be imported separately. All public helpers are released at the level of the project, so they can be imported by directly referencing the helper's .mjs file.

import {defineIdleProperty} from 'idlize/defineIdleProperty.mjs'
import {defineIdleProperties} from 'idlize/defineIdleProperties.mjs'
import {cIC, rIC} from 'idlize/idle-callback-polyfills.mjs'
import {IdleQueue} from 'idlize/IdleQueue.mjs'
import {IdleValue} from 'idlize/IdleValue.mjs'

Refer to each helper's documentation for examples and API usage details:

Browser Support

Chrome
Firefox
Safari
Edge
Internet Explorer
9+
Opera

This code has been tested and known to work in all major browsers as well as Internet Explorer back to version 9.

License

Apache 2.0

idlize's People

Contributors

adamsanderson avatar futurist avatar philipwalton 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  avatar  avatar  avatar  avatar

idlize's Issues

Remove polyfill

Is it possible to remove the polyfill from default inclusion? Given the use of mjs it seems to assume some sort of bundling is happening anyway, so it seems reasonable to let users polyfill requestIdleCallback themselves as they see fit.

If you'd like, I am happy to make a PR with the removal and docs.

Installation steps

Hello, first of all, thanks for making idlize!

I see that you suggest to use npm install -D idlize in order to install the library, is there a reason for that? I think it should be added as npm install idlize / yarn add idlize.

If that's the case, I can create a PR for it!

Thanks again,

Suggestion: priorities in IdleQueue

It would be nice to be able to add prioritized tasks to an IdleQueue.
We currently have a use case to preload components and would like to preload them by priority - not by order of insertion.
This could either be included in IdleQueue (with the default behavior of a regular queue when no priorities provided) or in a new class: IdlePriorityQueue.

I am willing to create a PR.

question about IdleQueue

am kinda not sure what options.minTaskTime suppose to be, is it in milliseconds, seconds, something else ?

also maybe am wrong but from what i understand is the idle time is where the main thread have no work to do, this way you can delay some of the work for later to make sure we get a smooth/fast experience.

however testing with something like

document.body.addEventListener('transitionend', () => {
    console.log('trans')
    this.queue.pushTask(() => {
        console.log('trans-idle')
    })
})

results in

screen shot 2018-09-22 at 10 34 48 am copy

as you can see the idle time could be a 1ms which is definitely far from idle, so am not sure how to setup the queue to only work when the browser is positively idle, maybe am missing something on what IDLE actually means so any help is appreciated.

mjs file throwing error when trying to upgrade from angular 12 to 13

We are trying to upgrade our angular from 12 to 13 with node 14.15.0 and facing the below error while giving npm start. Also tried the same with node 16.14.0, still facing the same error in npm start

ERROR in ./node_modules/@angular/platform-browser-dynamic/fesm2015/platform-browser-dynamic.mjs
Module not found: Error: Can't resolve '@angular/common' in '..\node_modules@angular\platform-browser-dynamic\fesm2015'

ERROR in ./node_modules/@angular/platform-browser/fesm2015/platform-browser.mjs
Module not found: Error: Can't resolve '@angular/common' in '..\node_modules@angular\platform-browser\fesm2015'

ERROR in ./node_modules/@angular/router/fesm2015/router.mjs
Module not found: Error: Can't resolve '@angular/common' in '..@angular\router\fesm2015'

ERROR in ./node_modules/@angular/platform-browser-dynamic/fesm2015/platform-browser-dynamic.mjs
Module not found: Error: Can't resolve '@angular/compiler' in '..\node_modules@angular\platform-browser-dynamic\fesm2015'

ERROR in ./node_modules/@angular/common/fesm2015/common.mjs
Module not found: Error: Can't resolve '@angular/core' in '..\node_modules@angular\common\fesm2015'

ERROR in ./node_modules/@angular/platform-browser-dynamic/fesm2015/platform-browser-dynamic.mjs
Module not found: Error: Can't resolve '@angular/core' in '..\node_modules@angular\platform-browser-dynamic\fesm2015'

ERROR in ./node_modules/@angular/platform-browser/fesm2015/platform-browser.mjs
Module not found: Error: Can't resolve '@angular/core' in '..\node_modules@angular\platform-browser\fesm2015'
ERROR in ./node_modules/@angular/router/fesm2015/router.mjs

Module not found: Error: Can't resolve '@angular/core' in '..\node_modules@angular\router\fesm2015'

ERROR in ./node_modules/@angular/platform-browser-dynamic/fesm2015/platform-browser-dynamic.mjs
Module not found: Error: Can't resolve '@angular/platform-browser' in '..\node_modules@angular\platform-browser-dynamic\fesm2015'

i 「wdm」: Failed to compile.

Below is the package.json

"dependencies": {
"@angular/animations": "^13.2.3",
"@angular/cdk": "^13.2.3",
"@angular/common": "^13.2.3",
"@angular/compiler": "^13.2.3",
"@angular/core": "^13.2.3",
"@angular/forms": "^13.2.3",
"@angular/http": "^7.2.15",
"@angular/material": "^13.2.3",
"@angular/platform-browser": "^13.2.3",
"@angular/platform-browser-dynamic": "^13.2.3",
"@angular/platform-server": "^13.2.3",
"@angular/router": "^13.2.3",
"@aspnet/signalr": "^1.1.4",
"@juggle/resize-observer": "^3.2.0",
"@ng-bootstrap/ng-bootstrap": "^10.0.0",
"@progress/kendo-angular-buttons": "^5.0.1",
"@progress/kendo-angular-charts": "^4.1.2",
"@progress/kendo-angular-common": "^1.2.1",
"@progress/kendo-angular-dateinputs": "^4.2.0",
"@progress/kendo-angular-dropdowns": "^4.2.3",
"@progress/kendo-angular-excel-export": "^3.0.1",
"@progress/kendo-angular-grid": "^4.5.0",
"@progress/kendo-angular-inputs": "^6.3.1",
"@progress/kendo-angular-l10n": "^2.0.0",
"@progress/kendo-angular-pdf-export": "^2.0.0",
"@progress/kendo-angular-popup": "^3.0.4",
"@progress/kendo-drawing": "^1.6.0",
"@progress/kendo-file-saver": "^1.0.7",
"@progress/kendo-theme-default": "^4.9.0",
"applicationinsights-js": "^1.0.20",
"bootstrap": "^5.1.2",
"core-js": "^3.21.1",
"expose-loader": "^0.7.5",
"hammerjs": "^2.0.8",
"jquery": "^3.6.0",
"mat-currency-format": "0.0.7",
"moment": "^2.24.0",
"moment-timezone": "^0.5.27",
"ngx-bootstrap": "^5.6.2",
"ngx-perfect-scrollbar": "^8.0.0",
"ngx-restangular": "^5.0.0",
"ngx-swiper-wrapper": "^8.0.2",
"regenerator-runtime": "^0.13.3",
"rxjs": "^7.5.4",
"rxjs-compat": "^6.5.3",
"sass": "^1.45.2",
"zone.js": "^0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "^13.2.4",
"@angular/cli": "^13.2.4",
"@angular/compiler-cli": "^13.2.3",
"@angular/language-service": "^13.2.3",
"@ngtools/webpack": "^8.3.20",
"@progress/kendo-angular-intl": "^2.0.0",
"@progress/kendo-data-query": "^1.5.2",
"@types/angular": "^1.6.57",
"@types/angular-animate": "^1.5.10",
"@types/angular-mocks": "^1.7.0",
"@types/angular-resource": "^1.5.15",
"@types/angular-route": "^1.7.0",
"@types/angular-sanitize": "^1.7.0",
"@types/applicationinsights-js": "^1.0.9",
"@types/google.analytics": "^0.0.40",
"@types/jasmine": "^3.10.3",
"@types/jquery": "^3.3.31",
"@types/lodash": "^4.14.149",
"@types/moment": "^2.13.0",
"@types/moment-timezone": "^0.5.12",
"@types/node": "^17.0.18",
"@types/webpack-env": "^1.14.1",
"angular-router-loader": "^0.8.5",
"angular2-template-loader": "^0.6.2",
"canonical-path": "^1.0.0",
"codelyzer": "^6.0.2",
"concurrently": "^5.0.1",
"copy-webpack-plugin": "^5.1.0",
"css-loader": "^3.3.0",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"file-loader": "^5.0.2",
"file-saver": "^2.0.2",
"gsap": "^3.7.1",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"http-server": "^0.12.0",
"install": "^0.13.0",
"jasmine-core": "^4.0.0",
"jasmine-spec-reporter": "^7.0.0",
"karma": "^6.3.16",
"karma-chrome-launcher": "^3.1.0",
"karma-cli": "^2.0.0",
"karma-jasmine": "^4.0.1",
"karma-jasmine-html-reporter": "^1.7.0",
"lodash": "^4.17.21",
"ng2-odometer": "^1.1.3",
"ngx-countdown": "^8.0.3",
"ngx-modialog": "^5.0.1",
"null-loader": "^3.0.0",
"protractor": "^7.0.0",
"raw-loader": "^4.0.0",
"rimraf": "^3.0.0",
"rollup": "^1.27.11",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-uglify": "^6.0.4",
"rxjs-tslint": "^0.1.8",
"sass-loader": "^8.0.0",
"style-loader": "^1.0.1",
"terser-webpack-plugin": "^2.3.0",
"to-string-loader": "^1.1.6",
"ts-loader": "^6.2.1",
"ts-node": "~8.5.4",
"tslint": "^6.1.3",
"typescript": "^4.4",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.9.0",
"webpack-merge": "^4.2.2",
"xlsx": "^0.17.2"
}
}

Tried clearing cache, deleted node_modules and package-lock, gave npm install again. Still facing the same issue

[IdleValue] Add valueOf method

Hi @philipwalton! Congratulations for your work on this lib!

I would like to suggest two possible improvements to IdleValue class. The first one came from the concept that JS Object prototype has a method called valueOf[1] that converts the object to a primitive value. I think that it can be very useful because it will allow code to behave like this:

const myIdleValue = new IdleValue(() => return 'example');
console.log(myIdleValue === 'example'); // true
console.log('my ' + myIdleValue); // my example

The second possible change is an approach closer of the actual implementation. getValue and setValue methods can be transformed in getter and setter methods.

class IdleValue {
   constructor(init) {
     // (...)
  }

  get value() {
    if (this.value_ === undefined) {
      this.cancleIdleInit_();
      this.value_ = this.init_();
    }
    return this.value_;
  }

  set value(param) {
    this.cancleIdleInit_();
    this.value_ = newValue;
  }

  cancleIdleInit_() {
    // (...)
  }
}

or even like this, if you want to keep compatibility with getValue and setValue methods

class IdleValue {
   constructor(init) {
     // (...)
  }

  get value() {
   this.getValue();
  }

  set value(param) {
    this.setValue(param);
  }

  getValue() {
    // (...)
  }

  setValue(param) {
    // (...)
  }

  cancleIdleInit_() {
    // (...)
  }
}

So the example will be:

const myIdleValue = new IdleValue(() => return 'example');
console.log(myIdleValue.value === 'example'); // true
console.log('my ' + myIdleValue.value); // my example
myIdleValue.value = 'new example';
console.log(myIdleValue) // new example

[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf

.mjs extension invalid for Angular/Typescript

Hi,

I've been attempting to use this package, but as the files are .mjs, angular/typescript are unable to use them, we get the following errors:

  >> ERROR in src/app/shared/services/until-idle.service.ts(2,36): error TS2307: Cannot find module 'idlize/defineIdleProperty.mjs'.
    >> src/app/shared/services/until-idle.service.ts(3,38): error TS2307: Cannot find module 'idlize/defineIdleProperties.mjs'.
    >> src/app/shared/services/until-idle.service.ts(4,26): error TS2307: Cannot find module 'idlize/idle-callback-polyfills.mjs'.
    >> src/app/shared/services/until-idle.service.ts(5,27): error TS2307: Cannot find module 'idlize/IdleQueue.mjs'.

We are using Angular 6 (Typescript).

Please can this package be converted to use .js rather than using .mjs? You might need to provide both .mjs/.js as this package will be used in other projects?

Is there a reason why you didn't opt for the standard import {IdleQueue} from 'idlize' syntax?

Having said that, I'm looking forward to using this (and blogging about it) on the work we're doing to increase performance on our site. Great work.

Thanks,

Suggestion: Include a IdleTask for simplifying some use cases of IdleQueue

Given generator's (two-way) coroutine design was designed in order to enable custom runners it would be good to have some runner built on top of IdleValue that can simplify writing.

Simple example:

const size = width * height * 4
const imageData = new Uint8Array(size)

// Just a simple whitenoise image generator
return new IdleTask(function*() {
  for (let i = 0 ; i < size ; i++) {
    // Allow scheduler to break this up as much as it needs
    yield
    imageData[i] = Math.floor(Math.random() * 256)
  }
  return imageData
})

Example implementation of IdleTask (doesn't handle things like const value = yield anotherIdleValue or other stuff like that though):

class IdleTask {
  constructor(genFunction) {
    this._job = genFunction()
    this._value = null
    this._ready = false

    const runUntilComplete = (idleDeadline) => {
      while (idleDeadline.timeRemaining() > 0) {
        const iterResult = this._job.next()
        if (iterResult.done) {
          this._ready = true
          this._value = iterResult.value
          return
        }
      }
      this._idleCallback = requestIdleCallback(runUntilComplete)
    }

    this._idleCallback = requestIdleCallback(runUntilComplete)
  }

  _runToCompletion() {
    while (true) {
      const iterResult = this._job.next()
      if (iterResult.done) {
        this._ready = true
        this._value = iterResult.value
        return this._value
      }
    }
  }

  getValue() {
    if (this._ready) {
      return this._value
    } else {
      cancelIdleCallback(this._idleCallback)
      return this._runToCompletion()
    }
  }
}

Typo in the IdleDeadline Class

I was reading the source and came across this class declaration:

/**
* A minimal shim of the native IdleDeadline class.
*/
class IdleDealine {

The class is called idleDealine but it shims the native idleDeadline implementation.

I presume the missing 'd' is a typo?

(BTW. Great article and module! It's a very interesting performance pattern.)

How to bind a task in queue with an user interaction event

There are some common cases like

  • A mobile menu to be initiated and used when user click on the button
  • A search JS overlay need to be initiated and when user input the search, it will start interact with users immediately

I'm looking a way to optimize some UI JS for those and found this together with
https://github.com/hiroki0525/idle-task

Both are nice idea and exactly what I'm approaching. However in both cases, I can not see an interface API which allow to do these when CPU is idle while allow the initialization can be triggered immediately if users interact (and it was not initiated).

I only see a similar wrapper for Value Initialization and it does not work with queue. Do you have any idea? @philipwalton @adamsanderson @zachleat @PaulKinlan @mathiasbynens @futurist

ReferenceError: Can't find variable: cancelIdleCallback Script Element

is there any reason to avoid for cancelIdleCallback checking here:
https://github.com/GoogleChromeLabs/idlize/blob/master/idle-callback-polyfills.mjs#L80
it creates problems when a page has requestIdleCallback but might not have cancelIdleCallback function

can we check here for cancelIdleCallback as well ?
e.g.:
const supportsRequestIdleCallback_ = typeof requestIdleCallback === 'function' && typeof cancelIdleCallback === "function";

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.