frame-scheduling
Advanced tools
Comparing version 0.7.0 to 0.7.1
@@ -0,1 +1,2 @@ | ||
import { Defer } from "./defer"; | ||
export declare const P_LOWER = 1; | ||
@@ -6,2 +7,5 @@ export declare const P_LOW = 3; | ||
export declare const P_IMPORTANT = 10; | ||
export declare const createFrameScheduling: (defer?: Defer, lifeFrame?: number) => (callback: () => void, { priority }?: { | ||
priority?: number | undefined; | ||
}) => void; | ||
declare const _default: (callback: () => void, { priority }?: { | ||
@@ -8,0 +12,0 @@ priority?: number | undefined; |
@@ -1,18 +0,5 @@ | ||
var context = typeof window !== "undefined" ? window : global; | ||
var defer; | ||
if ("requestAnimationFrame" in context) { | ||
defer = requestAnimationFrame.bind(context); | ||
} | ||
else if ("setImmediate" in context) { | ||
defer = setImmediate.bind(context); | ||
} | ||
else { | ||
defer = setTimeout.bind(context); | ||
} | ||
var TIME_LIFE_FRAME = 16; // 16ms === 60fps | ||
var P_LOWER = 1; | ||
var P_LOW = 3; | ||
var P_NORMAL = 5; | ||
var P_HIGH = 7; | ||
var P_IMPORTANT = 10; | ||
var getParentIndex = function (childIndex) { return Math.floor((childIndex - 1) / 2); }; | ||
var getRightChildIndex = function (parentIndex) { return 2 * parentIndex + 2; }; | ||
var hasParent = function (childIndex) { return getParentIndex(childIndex) >= 0; }; | ||
var getLeftChildIndex = function (parentIndex) { return 2 * parentIndex + 1; }; | ||
var PriorityUniqQueue = /** @class */ (function () { | ||
@@ -63,6 +50,6 @@ function PriorityUniqQueue() { | ||
var currentIndex = customStartIndex || this.heapContainer.length - 1; | ||
while (this.hasParent(currentIndex) | ||
&& !this.pairIsInCorrectOrder(this.heapContainer[this.getParentIndex(currentIndex)], this.heapContainer[currentIndex])) { | ||
this.swap(currentIndex, this.getParentIndex(currentIndex)); | ||
currentIndex = this.getParentIndex(currentIndex); | ||
while (hasParent(currentIndex) && | ||
!this.pairIsInCorrectOrder(this.heapContainer[getParentIndex(currentIndex)], this.heapContainer[currentIndex])) { | ||
this.swap(currentIndex, getParentIndex(currentIndex)); | ||
currentIndex = getParentIndex(currentIndex); | ||
} | ||
@@ -73,9 +60,9 @@ }; | ||
var nextIndex = null; | ||
while (this.hasLeftChild(currentIndex)) { | ||
if (this.hasRightChild(currentIndex) | ||
&& this.pairIsInCorrectOrder(this.rightChild(currentIndex), this.leftChild(currentIndex))) { | ||
nextIndex = this.getRightChildIndex(currentIndex); | ||
while (getLeftChildIndex(currentIndex) < this.heapContainer.length) { | ||
if (getRightChildIndex(currentIndex) < this.heapContainer.length && | ||
this.pairIsInCorrectOrder(this.heapContainer[getRightChildIndex(currentIndex)], this.heapContainer[getLeftChildIndex(currentIndex)])) { | ||
nextIndex = getRightChildIndex(currentIndex); | ||
} | ||
else { | ||
nextIndex = this.getLeftChildIndex(currentIndex); | ||
nextIndex = getLeftChildIndex(currentIndex); | ||
} | ||
@@ -92,26 +79,2 @@ if (this.pairIsInCorrectOrder(this.heapContainer[currentIndex], this.heapContainer[nextIndex])) { | ||
}; | ||
PriorityUniqQueue.prototype.getLeftChildIndex = function (parentIndex) { | ||
return (2 * parentIndex) + 1; | ||
}; | ||
PriorityUniqQueue.prototype.getRightChildIndex = function (parentIndex) { | ||
return (2 * parentIndex) + 2; | ||
}; | ||
PriorityUniqQueue.prototype.getParentIndex = function (childIndex) { | ||
return Math.floor((childIndex - 1) / 2); | ||
}; | ||
PriorityUniqQueue.prototype.hasParent = function (childIndex) { | ||
return this.getParentIndex(childIndex) >= 0; | ||
}; | ||
PriorityUniqQueue.prototype.hasLeftChild = function (parentIndex) { | ||
return this.getLeftChildIndex(parentIndex) < this.heapContainer.length; | ||
}; | ||
PriorityUniqQueue.prototype.hasRightChild = function (parentIndex) { | ||
return this.getRightChildIndex(parentIndex) < this.heapContainer.length; | ||
}; | ||
PriorityUniqQueue.prototype.leftChild = function (parentIndex) { | ||
return this.heapContainer[this.getLeftChildIndex(parentIndex)]; | ||
}; | ||
PriorityUniqQueue.prototype.rightChild = function (parentIndex) { | ||
return this.heapContainer[this.getRightChildIndex(parentIndex)]; | ||
}; | ||
PriorityUniqQueue.prototype.swap = function (indexOne, indexTwo) { | ||
@@ -124,2 +87,3 @@ var tmp = this.heapContainer[indexTwo]; | ||
}()); | ||
var LinkedList = /** @class */ (function () { | ||
@@ -134,3 +98,3 @@ function LinkedList() { | ||
next: null, | ||
value: value, | ||
value: value | ||
}; | ||
@@ -159,3 +123,24 @@ if (this.length === 0) { | ||
}()); | ||
var frameScheduling = function () { | ||
var context = typeof window !== "undefined" ? window : global; | ||
var defer; | ||
if ("requestAnimationFrame" in context) { | ||
defer = requestAnimationFrame; | ||
} | ||
else if ("setImmediate" in context) { | ||
defer = context.setImmediate; | ||
} | ||
else { | ||
defer = setTimeout; | ||
} | ||
var TIME_LIFE_FRAME = 16; // 16ms === 60fps | ||
var P_LOWER = 1; | ||
var P_LOW = 3; | ||
var P_NORMAL = 5; | ||
var P_HIGH = 7; | ||
var P_IMPORTANT = 10; | ||
var createFrameScheduling = function (defer$1, lifeFrame) { | ||
if (defer$1 === void 0) { defer$1 = defer; } | ||
if (lifeFrame === void 0) { lifeFrame = TIME_LIFE_FRAME; } | ||
var heapJobs = new PriorityUniqQueue(); | ||
@@ -165,14 +150,13 @@ var deferScheduled = false; | ||
if (!deferScheduled) { | ||
defer(runJobs); | ||
deferScheduled = true; | ||
defer$1(runJobs); | ||
} | ||
deferScheduled = true; | ||
}; | ||
var addJob = function (callback, priority) { | ||
var getJob = heapJobs.get(priority); | ||
var newLinkedList; | ||
if (!getJob) { | ||
newLinkedList = new LinkedList(); | ||
heapJobs.add(priority, newLinkedList); | ||
var job = heapJobs.get(priority); | ||
if (!job) { | ||
job = new LinkedList(); | ||
heapJobs.add(priority, job); | ||
} | ||
(getJob || newLinkedList).push(callback); | ||
job.push(callback); | ||
}; | ||
@@ -182,3 +166,3 @@ var runJobs = function () { | ||
while (true) { | ||
if (heapJobs.isEmpty() || Date.now() - timeRun > TIME_LIFE_FRAME) { | ||
if (heapJobs.isEmpty() || Date.now() - timeRun > lifeFrame) { | ||
break; | ||
@@ -188,5 +172,4 @@ } | ||
var jobs = heapJobs.peek(); | ||
var job = jobs.shift(); | ||
try { | ||
job(); | ||
(jobs.shift())(); | ||
} | ||
@@ -213,5 +196,5 @@ catch (e) { | ||
}; | ||
var frameScheduling$1 = frameScheduling(); | ||
var frameScheduling = createFrameScheduling(); | ||
export default frameScheduling$1; | ||
export { P_LOWER, P_LOW, P_NORMAL, P_HIGH, P_IMPORTANT }; | ||
export default frameScheduling; | ||
export { P_HIGH, P_IMPORTANT, P_LOW, P_LOWER, P_NORMAL, createFrameScheduling }; |
@@ -1,18 +0,5 @@ | ||
const context = typeof window !== "undefined" ? window : global; | ||
let defer; | ||
if ("requestAnimationFrame" in context) { | ||
defer = requestAnimationFrame.bind(context); | ||
} | ||
else if ("setImmediate" in context) { | ||
defer = setImmediate.bind(context); | ||
} | ||
else { | ||
defer = setTimeout.bind(context); | ||
} | ||
const TIME_LIFE_FRAME = 16; // 16ms === 60fps | ||
const P_LOWER = 1; | ||
const P_LOW = 3; | ||
const P_NORMAL = 5; | ||
const P_HIGH = 7; | ||
const P_IMPORTANT = 10; | ||
const getParentIndex = (childIndex) => Math.floor((childIndex - 1) / 2); | ||
const getRightChildIndex = (parentIndex) => 2 * parentIndex + 2; | ||
const hasParent = (childIndex) => getParentIndex(childIndex) >= 0; | ||
const getLeftChildIndex = (parentIndex) => 2 * parentIndex + 1; | ||
class PriorityUniqQueue { | ||
@@ -63,6 +50,6 @@ constructor() { | ||
let currentIndex = customStartIndex || this.heapContainer.length - 1; | ||
while (this.hasParent(currentIndex) | ||
&& !this.pairIsInCorrectOrder(this.heapContainer[this.getParentIndex(currentIndex)], this.heapContainer[currentIndex])) { | ||
this.swap(currentIndex, this.getParentIndex(currentIndex)); | ||
currentIndex = this.getParentIndex(currentIndex); | ||
while (hasParent(currentIndex) && | ||
!this.pairIsInCorrectOrder(this.heapContainer[getParentIndex(currentIndex)], this.heapContainer[currentIndex])) { | ||
this.swap(currentIndex, getParentIndex(currentIndex)); | ||
currentIndex = getParentIndex(currentIndex); | ||
} | ||
@@ -73,9 +60,9 @@ } | ||
let nextIndex = null; | ||
while (this.hasLeftChild(currentIndex)) { | ||
if (this.hasRightChild(currentIndex) | ||
&& this.pairIsInCorrectOrder(this.rightChild(currentIndex), this.leftChild(currentIndex))) { | ||
nextIndex = this.getRightChildIndex(currentIndex); | ||
while (getLeftChildIndex(currentIndex) < this.heapContainer.length) { | ||
if (getRightChildIndex(currentIndex) < this.heapContainer.length && | ||
this.pairIsInCorrectOrder(this.heapContainer[getRightChildIndex(currentIndex)], this.heapContainer[getLeftChildIndex(currentIndex)])) { | ||
nextIndex = getRightChildIndex(currentIndex); | ||
} | ||
else { | ||
nextIndex = this.getLeftChildIndex(currentIndex); | ||
nextIndex = getLeftChildIndex(currentIndex); | ||
} | ||
@@ -92,26 +79,2 @@ if (this.pairIsInCorrectOrder(this.heapContainer[currentIndex], this.heapContainer[nextIndex])) { | ||
} | ||
getLeftChildIndex(parentIndex) { | ||
return (2 * parentIndex) + 1; | ||
} | ||
getRightChildIndex(parentIndex) { | ||
return (2 * parentIndex) + 2; | ||
} | ||
getParentIndex(childIndex) { | ||
return Math.floor((childIndex - 1) / 2); | ||
} | ||
hasParent(childIndex) { | ||
return this.getParentIndex(childIndex) >= 0; | ||
} | ||
hasLeftChild(parentIndex) { | ||
return this.getLeftChildIndex(parentIndex) < this.heapContainer.length; | ||
} | ||
hasRightChild(parentIndex) { | ||
return this.getRightChildIndex(parentIndex) < this.heapContainer.length; | ||
} | ||
leftChild(parentIndex) { | ||
return this.heapContainer[this.getLeftChildIndex(parentIndex)]; | ||
} | ||
rightChild(parentIndex) { | ||
return this.heapContainer[this.getRightChildIndex(parentIndex)]; | ||
} | ||
swap(indexOne, indexTwo) { | ||
@@ -123,2 +86,3 @@ const tmp = this.heapContainer[indexTwo]; | ||
} | ||
class LinkedList { | ||
@@ -133,3 +97,3 @@ constructor() { | ||
next: null, | ||
value, | ||
value | ||
}; | ||
@@ -157,3 +121,22 @@ if (this.length === 0) { | ||
} | ||
const frameScheduling = () => { | ||
const context = typeof window !== "undefined" ? window : global; | ||
let defer; | ||
if ("requestAnimationFrame" in context) { | ||
defer = requestAnimationFrame; | ||
} | ||
else if ("setImmediate" in context) { | ||
defer = context.setImmediate; | ||
} | ||
else { | ||
defer = setTimeout; | ||
} | ||
const TIME_LIFE_FRAME = 16; // 16ms === 60fps | ||
const P_LOWER = 1; | ||
const P_LOW = 3; | ||
const P_NORMAL = 5; | ||
const P_HIGH = 7; | ||
const P_IMPORTANT = 10; | ||
const createFrameScheduling = (defer$1 = defer, lifeFrame = TIME_LIFE_FRAME) => { | ||
const heapJobs = new PriorityUniqQueue(); | ||
@@ -163,14 +146,13 @@ let deferScheduled = false; | ||
if (!deferScheduled) { | ||
defer(runJobs); | ||
deferScheduled = true; | ||
defer$1(runJobs); | ||
} | ||
deferScheduled = true; | ||
}; | ||
const addJob = (callback, priority) => { | ||
const getJob = heapJobs.get(priority); | ||
let newLinkedList; | ||
if (!getJob) { | ||
newLinkedList = new LinkedList(); | ||
heapJobs.add(priority, newLinkedList); | ||
let job = heapJobs.get(priority); | ||
if (!job) { | ||
job = new LinkedList(); | ||
heapJobs.add(priority, job); | ||
} | ||
(getJob || newLinkedList).push(callback); | ||
job.push(callback); | ||
}; | ||
@@ -180,3 +162,3 @@ const runJobs = () => { | ||
while (true) { | ||
if (heapJobs.isEmpty() || Date.now() - timeRun > TIME_LIFE_FRAME) { | ||
if (heapJobs.isEmpty() || Date.now() - timeRun > lifeFrame) { | ||
break; | ||
@@ -186,5 +168,4 @@ } | ||
const jobs = heapJobs.peek(); | ||
const job = jobs.shift(); | ||
try { | ||
job(); | ||
(jobs.shift())(); | ||
} | ||
@@ -210,5 +191,5 @@ catch (e) { | ||
}; | ||
var frameScheduling$1 = frameScheduling(); | ||
var frameScheduling = createFrameScheduling(); | ||
export default frameScheduling$1; | ||
export { P_LOWER, P_LOW, P_NORMAL, P_HIGH, P_IMPORTANT }; | ||
export default frameScheduling; | ||
export { P_HIGH, P_IMPORTANT, P_LOW, P_LOWER, P_NORMAL, createFrameScheduling }; |
@@ -5,19 +5,6 @@ 'use strict'; | ||
var context = typeof window !== "undefined" ? window : global; | ||
var defer; | ||
if ("requestAnimationFrame" in context) { | ||
defer = requestAnimationFrame.bind(context); | ||
} | ||
else if ("setImmediate" in context) { | ||
defer = setImmediate.bind(context); | ||
} | ||
else { | ||
defer = setTimeout.bind(context); | ||
} | ||
var TIME_LIFE_FRAME = 16; // 16ms === 60fps | ||
var P_LOWER = 1; | ||
var P_LOW = 3; | ||
var P_NORMAL = 5; | ||
var P_HIGH = 7; | ||
var P_IMPORTANT = 10; | ||
var getParentIndex = function (childIndex) { return Math.floor((childIndex - 1) / 2); }; | ||
var getRightChildIndex = function (parentIndex) { return 2 * parentIndex + 2; }; | ||
var hasParent = function (childIndex) { return getParentIndex(childIndex) >= 0; }; | ||
var getLeftChildIndex = function (parentIndex) { return 2 * parentIndex + 1; }; | ||
var PriorityUniqQueue = /** @class */ (function () { | ||
@@ -68,6 +55,6 @@ function PriorityUniqQueue() { | ||
var currentIndex = customStartIndex || this.heapContainer.length - 1; | ||
while (this.hasParent(currentIndex) | ||
&& !this.pairIsInCorrectOrder(this.heapContainer[this.getParentIndex(currentIndex)], this.heapContainer[currentIndex])) { | ||
this.swap(currentIndex, this.getParentIndex(currentIndex)); | ||
currentIndex = this.getParentIndex(currentIndex); | ||
while (hasParent(currentIndex) && | ||
!this.pairIsInCorrectOrder(this.heapContainer[getParentIndex(currentIndex)], this.heapContainer[currentIndex])) { | ||
this.swap(currentIndex, getParentIndex(currentIndex)); | ||
currentIndex = getParentIndex(currentIndex); | ||
} | ||
@@ -78,9 +65,9 @@ }; | ||
var nextIndex = null; | ||
while (this.hasLeftChild(currentIndex)) { | ||
if (this.hasRightChild(currentIndex) | ||
&& this.pairIsInCorrectOrder(this.rightChild(currentIndex), this.leftChild(currentIndex))) { | ||
nextIndex = this.getRightChildIndex(currentIndex); | ||
while (getLeftChildIndex(currentIndex) < this.heapContainer.length) { | ||
if (getRightChildIndex(currentIndex) < this.heapContainer.length && | ||
this.pairIsInCorrectOrder(this.heapContainer[getRightChildIndex(currentIndex)], this.heapContainer[getLeftChildIndex(currentIndex)])) { | ||
nextIndex = getRightChildIndex(currentIndex); | ||
} | ||
else { | ||
nextIndex = this.getLeftChildIndex(currentIndex); | ||
nextIndex = getLeftChildIndex(currentIndex); | ||
} | ||
@@ -97,26 +84,2 @@ if (this.pairIsInCorrectOrder(this.heapContainer[currentIndex], this.heapContainer[nextIndex])) { | ||
}; | ||
PriorityUniqQueue.prototype.getLeftChildIndex = function (parentIndex) { | ||
return (2 * parentIndex) + 1; | ||
}; | ||
PriorityUniqQueue.prototype.getRightChildIndex = function (parentIndex) { | ||
return (2 * parentIndex) + 2; | ||
}; | ||
PriorityUniqQueue.prototype.getParentIndex = function (childIndex) { | ||
return Math.floor((childIndex - 1) / 2); | ||
}; | ||
PriorityUniqQueue.prototype.hasParent = function (childIndex) { | ||
return this.getParentIndex(childIndex) >= 0; | ||
}; | ||
PriorityUniqQueue.prototype.hasLeftChild = function (parentIndex) { | ||
return this.getLeftChildIndex(parentIndex) < this.heapContainer.length; | ||
}; | ||
PriorityUniqQueue.prototype.hasRightChild = function (parentIndex) { | ||
return this.getRightChildIndex(parentIndex) < this.heapContainer.length; | ||
}; | ||
PriorityUniqQueue.prototype.leftChild = function (parentIndex) { | ||
return this.heapContainer[this.getLeftChildIndex(parentIndex)]; | ||
}; | ||
PriorityUniqQueue.prototype.rightChild = function (parentIndex) { | ||
return this.heapContainer[this.getRightChildIndex(parentIndex)]; | ||
}; | ||
PriorityUniqQueue.prototype.swap = function (indexOne, indexTwo) { | ||
@@ -129,2 +92,3 @@ var tmp = this.heapContainer[indexTwo]; | ||
}()); | ||
var LinkedList = /** @class */ (function () { | ||
@@ -139,3 +103,3 @@ function LinkedList() { | ||
next: null, | ||
value: value, | ||
value: value | ||
}; | ||
@@ -164,3 +128,24 @@ if (this.length === 0) { | ||
}()); | ||
var frameScheduling = function () { | ||
var context = typeof window !== "undefined" ? window : global; | ||
var defer; | ||
if ("requestAnimationFrame" in context) { | ||
defer = requestAnimationFrame; | ||
} | ||
else if ("setImmediate" in context) { | ||
defer = context.setImmediate; | ||
} | ||
else { | ||
defer = setTimeout; | ||
} | ||
var TIME_LIFE_FRAME = 16; // 16ms === 60fps | ||
var P_LOWER = 1; | ||
var P_LOW = 3; | ||
var P_NORMAL = 5; | ||
var P_HIGH = 7; | ||
var P_IMPORTANT = 10; | ||
var createFrameScheduling = function (defer$1, lifeFrame) { | ||
if (defer$1 === void 0) { defer$1 = defer; } | ||
if (lifeFrame === void 0) { lifeFrame = TIME_LIFE_FRAME; } | ||
var heapJobs = new PriorityUniqQueue(); | ||
@@ -170,14 +155,13 @@ var deferScheduled = false; | ||
if (!deferScheduled) { | ||
defer(runJobs); | ||
deferScheduled = true; | ||
defer$1(runJobs); | ||
} | ||
deferScheduled = true; | ||
}; | ||
var addJob = function (callback, priority) { | ||
var getJob = heapJobs.get(priority); | ||
var newLinkedList; | ||
if (!getJob) { | ||
newLinkedList = new LinkedList(); | ||
heapJobs.add(priority, newLinkedList); | ||
var job = heapJobs.get(priority); | ||
if (!job) { | ||
job = new LinkedList(); | ||
heapJobs.add(priority, job); | ||
} | ||
(getJob || newLinkedList).push(callback); | ||
job.push(callback); | ||
}; | ||
@@ -187,3 +171,3 @@ var runJobs = function () { | ||
while (true) { | ||
if (heapJobs.isEmpty() || Date.now() - timeRun > TIME_LIFE_FRAME) { | ||
if (heapJobs.isEmpty() || Date.now() - timeRun > lifeFrame) { | ||
break; | ||
@@ -193,5 +177,4 @@ } | ||
var jobs = heapJobs.peek(); | ||
var job = jobs.shift(); | ||
try { | ||
job(); | ||
(jobs.shift())(); | ||
} | ||
@@ -218,9 +201,10 @@ catch (e) { | ||
}; | ||
var frameScheduling$1 = frameScheduling(); | ||
var frameScheduling = createFrameScheduling(); | ||
exports.P_HIGH = P_HIGH; | ||
exports.P_IMPORTANT = P_IMPORTANT; | ||
exports.P_LOW = P_LOW; | ||
exports.P_LOWER = P_LOWER; | ||
exports.P_LOW = P_LOW; | ||
exports.P_NORMAL = P_NORMAL; | ||
exports.P_HIGH = P_HIGH; | ||
exports.P_IMPORTANT = P_IMPORTANT; | ||
exports.default = frameScheduling$1; | ||
exports.createFrameScheduling = createFrameScheduling; | ||
exports.default = frameScheduling; |
{ | ||
"name": "frame-scheduling", | ||
"version": "0.7.0", | ||
"version": "0.7.1", | ||
"description": "Asynchronous start of functions in JS. Supports priority and interrupt execution every 16 milliseconds, to achieve 60fps.", | ||
"scripts": { | ||
"build": "rollup -c", | ||
"size": "npm run build && size-limit", | ||
"prepublishOnly": "npm run build", | ||
"test": "jest", | ||
"test": "npm run test:unit && npm run size", | ||
"test:unit": "jest", | ||
"test:coverage": "jest --coverage", | ||
@@ -13,3 +15,6 @@ "test:watch": "jest --watch", | ||
}, | ||
"files": [ "dist", "src" ], | ||
"files": [ | ||
"dist", | ||
"src" | ||
], | ||
"main": "dist/frameScheduling.js", | ||
@@ -24,2 +29,8 @@ "module": "dist/frameScheduling.esm.js", | ||
"keywords": [], | ||
"size-limit": [ | ||
{ | ||
"path": "dist/frameScheduling.js", | ||
"limit": "930 B" | ||
} | ||
], | ||
"author": "Andey Marchenko <tom910ru@gmail.com>", | ||
@@ -32,13 +43,14 @@ "license": "MIT", | ||
"devDependencies": { | ||
"@types/jest": "^21.1.4", | ||
"@types/node": "^8.0.46", | ||
"coveralls": "^3.0.0", | ||
"jest": "^21.2.1", | ||
"prettier": "1.7.4", | ||
"rollup": "^0.64.1", | ||
"rollup-plugin-typescript2": "^0.16.1", | ||
"ts-jest": "^21.1.4", | ||
"tslint": "^5.8.0", | ||
"typescript": "^3.0.1" | ||
"@types/jest": "^24.0.13", | ||
"@types/node": "^12.0.4", | ||
"coveralls": "^3.0.3", | ||
"jest": "^24.8.0", | ||
"prettier": "1.17.1", | ||
"rollup": "^1.13.1", | ||
"rollup-plugin-typescript2": "^0.21.1", | ||
"size-limit": "^1.3.5", | ||
"ts-jest": "^24.0.2", | ||
"tslint": "^5.17.0", | ||
"typescript": "^3.5.1" | ||
} | ||
} |
@@ -1,11 +0,19 @@ | ||
# Frame Scheduling | ||
[![Build Status](https://travis-ci.org/Tom910/frame-scheduling.svg?branch=master)](https://travis-ci.org/Tom910/frame-scheduling) | ||
[![Coverage Status](https://coveralls.io/repos/github/Tom910/frame-scheduling/badge.svg?branch=master)](https://coveralls.io/github/Tom910/frame-scheduling?branch=master) | ||
# Frame Scheduling | ||
A tiny module which allows run a non-blocking layout many tasks. | ||
* **Fast.** Contains low overhead and optimized for running lots of tasks without drop fps | ||
* **Small.** 930 B (minified and gzipped). No dependencies. It uses [Size Limit](https://github.com/ai/size-limit) to control size. | ||
* **Priority** Separate tasks into different priorities. Try to complete priority tasks as quickly as possible. | ||
* **Isomorphic.** work in browser and node js. | ||
```js | ||
import frameScheduling, { P_IMPORTANT } from 'frame-scheduling'; | ||
frameScheduling(() => { Action() }, { priority: P_IMPORTANT }); | ||
frameScheduling(() => { console.log('async task') }); | ||
``` | ||
[Demo](https://codesandbox.io/s/admiring-ride-jdoq0) | ||
@@ -24,4 +32,4 @@ Asynchronous running tasks in JavaScript based on requestAnimationFrame. Supports priority and interrupt execution every 16 milliseconds, to achieve 60fps. | ||
## Example | ||
### Priority | ||
## Priority | ||
```js | ||
@@ -31,8 +39,11 @@ import frameScheduling, { P_IMPORTANT, P_LOW } from 'frame-scheduling'; | ||
frameScheduling(() => { result.push('Ember') }, { priority: P_LOW }) | ||
frameScheduling(() => { result.push('Angular') }) | ||
frameScheduling(() => { result.push('React') }, { priority: P_IMPORTANT }) | ||
frameScheduling(() => { result.push('A') }, { priority: P_LOW }) | ||
frameScheduling(() => { result.push('B') }) | ||
frameScheduling(() => { result.push('C') }, { priority: P_IMPORTANT }) | ||
frameScheduling(() => { result.push('D') }, { priority: 1000 }) | ||
console.log(result) // > ['React', 'Angular', 'Ember'] | ||
// after doing | ||
console.log(result) // > ['D', 'C', 'B', 'A'] | ||
``` | ||
perform priority tasks first | ||
@@ -43,17 +54,18 @@ ### framing | ||
frameScheduling(() => 'function 1') // light < 1ms exec | ||
frameScheduling(() => 'function 2') // heavy > 17ms exec | ||
frameScheduling(() => 'function 3') // heavy > 17ms exec | ||
frameScheduling(() => 'function 4') // light < 1ms exec | ||
frameScheduling(() => 'function 5') // light < 1ms exec | ||
frameScheduling(() => lightFunction()) // light < 1ms exec | ||
frameScheduling(() => heavyFunction()) // heavy > 17ms exec | ||
frameScheduling(() => heavyFunction2()) // heavy > 17ms exec | ||
frameScheduling(() => lightFunction2()) // light < 1ms exec | ||
frameScheduling(() => lightFunction3()) // light < 1ms exec | ||
/* | ||
Runs in frame | ||
| function 1 | ||
| function 2 | ||
| function 3 | ||
| function 4 | ||
| function 5 | ||
| lightFunction | ||
| heavyFunction | ||
| heavyFunction2 | ||
| lightFunction2 | ||
| lightFunction3 | ||
*/ | ||
``` | ||
frame-scheduling aims to achieve 60 fps | ||
@@ -60,0 +72,0 @@ ## Options |
@@ -1,12 +0,5 @@ | ||
const context = typeof window !== "undefined" ? window : global; | ||
import { PriorityUniqQueue } from "./priorityUniqQueue"; | ||
import { LinkedList } from "./linkedList"; | ||
import { defer as defaultDefer, Defer } from "./defer"; | ||
let defer: (f: () => void) => void; | ||
if ("requestAnimationFrame" in context) { | ||
defer = requestAnimationFrame.bind(context); | ||
} else if ("setImmediate" in context) { | ||
defer = setImmediate.bind(context); | ||
} else { | ||
defer = setTimeout.bind(context); | ||
} | ||
const TIME_LIFE_FRAME = 16; // 16ms === 60fps | ||
@@ -20,196 +13,6 @@ | ||
interface QueueItem<T> { priority: number; value: T; } | ||
class PriorityUniqQueue<T> { | ||
private heapContainer: Array<QueueItem<T>>; | ||
private hashPriority: Record<string, T>; | ||
constructor() { | ||
this.heapContainer = []; | ||
this.hashPriority = Object.create(null); | ||
} | ||
public peek() { | ||
return this.heapContainer[0].value; | ||
} | ||
public poll() { | ||
let item; | ||
if (this.heapContainer.length === 1) { | ||
item = (this.heapContainer.pop() as QueueItem<T>); | ||
} else { | ||
item = this.heapContainer[0]; | ||
this.heapContainer[0] = (this.heapContainer.pop() as QueueItem<T>); | ||
this.heapifyDown(); | ||
} | ||
delete this.hashPriority[item.priority]; | ||
return item.value; | ||
} | ||
public add(priority: number, value: T) { | ||
this.heapContainer.push({ priority, value }); | ||
this.heapifyUp(); | ||
this.hashPriority[priority] = value; | ||
} | ||
public isEmpty() { | ||
return !this.heapContainer.length; | ||
} | ||
public get(priority: number) { | ||
return this.hashPriority[priority]; | ||
} | ||
public rising() { | ||
const keys = Object.keys(this.hashPriority); | ||
for (let i = keys.length; i > 0; i--) { | ||
const key = keys[i - 1]; | ||
this.hashPriority[Number(key) + 1] = this.hashPriority[key]; | ||
delete this.hashPriority[key]; | ||
} | ||
for (let j = 0; j < this.heapContainer.length; j++) { | ||
this.heapContainer[j].priority += 1; | ||
} | ||
} | ||
private heapifyUp(customStartIndex?: number) { | ||
let currentIndex = customStartIndex || this.heapContainer.length - 1; | ||
while ( | ||
this.hasParent(currentIndex) | ||
&& !this.pairIsInCorrectOrder( | ||
this.heapContainer[this.getParentIndex(currentIndex)], | ||
this.heapContainer[currentIndex], | ||
) | ||
) { | ||
this.swap(currentIndex, this.getParentIndex(currentIndex)); | ||
currentIndex = this.getParentIndex(currentIndex); | ||
} | ||
} | ||
private heapifyDown(customStartIndex?: number) { | ||
let currentIndex = customStartIndex || 0; | ||
let nextIndex = null; | ||
while (this.hasLeftChild(currentIndex)) { | ||
if ( | ||
this.hasRightChild(currentIndex) | ||
&& this.pairIsInCorrectOrder(this.rightChild(currentIndex), this.leftChild(currentIndex)) | ||
) { | ||
nextIndex = this.getRightChildIndex(currentIndex); | ||
} else { | ||
nextIndex = this.getLeftChildIndex(currentIndex); | ||
} | ||
if (this.pairIsInCorrectOrder( | ||
this.heapContainer[currentIndex], | ||
this.heapContainer[nextIndex], | ||
)) { | ||
break; | ||
} | ||
this.swap(currentIndex, nextIndex); | ||
currentIndex = nextIndex; | ||
} | ||
} | ||
private pairIsInCorrectOrder(firstElement: QueueItem<T>, secondElement: QueueItem<T>) { | ||
return firstElement.priority >= secondElement.priority; | ||
} | ||
private getLeftChildIndex(parentIndex: number) { | ||
return (2 * parentIndex) + 1; | ||
} | ||
private getRightChildIndex(parentIndex: number) { | ||
return (2 * parentIndex) + 2; | ||
} | ||
private getParentIndex(childIndex: number) { | ||
return Math.floor((childIndex - 1) / 2); | ||
} | ||
private hasParent(childIndex: number) { | ||
return this.getParentIndex(childIndex) >= 0; | ||
} | ||
private hasLeftChild(parentIndex: number) { | ||
return this.getLeftChildIndex(parentIndex) < this.heapContainer.length; | ||
} | ||
private hasRightChild(parentIndex: number) { | ||
return this.getRightChildIndex(parentIndex) < this.heapContainer.length; | ||
} | ||
private leftChild(parentIndex: number) { | ||
return this.heapContainer[this.getLeftChildIndex(parentIndex)]; | ||
} | ||
private rightChild(parentIndex: number) { | ||
return this.heapContainer[this.getRightChildIndex(parentIndex)]; | ||
} | ||
private swap(indexOne: number, indexTwo: number) { | ||
const tmp = this.heapContainer[indexTwo]; | ||
this.heapContainer[indexTwo] = this.heapContainer[indexOne]; | ||
this.heapContainer[indexOne] = tmp; | ||
} | ||
} | ||
interface ListNode { | ||
value: () => void; | ||
next: ListNode | null; | ||
} | ||
class LinkedList { | ||
private length: number; | ||
private head: ListNode | null; | ||
private last: ListNode | null; | ||
constructor() { | ||
this.head = null; | ||
this.last = null; | ||
this.length = 0; | ||
} | ||
public push(value: () => void) { | ||
const node: ListNode = { | ||
next: null, | ||
value, | ||
}; | ||
if (this.length === 0) { | ||
this.head = node; | ||
this.last = node; | ||
} else { | ||
(this.last as ListNode).next = node; | ||
this.last = node; | ||
} | ||
this.length++; | ||
} | ||
public shift() { | ||
const currentHead = this.head as ListNode; | ||
const value = currentHead.value; | ||
this.head = currentHead.next; | ||
this.length--; | ||
return value; | ||
} | ||
public isEmpty() { | ||
return this.length === 0; | ||
} | ||
} | ||
const frameScheduling = () => { | ||
export const createFrameScheduling = ( | ||
defer: Defer = defaultDefer, | ||
lifeFrame: number = TIME_LIFE_FRAME | ||
) => { | ||
const heapJobs = new PriorityUniqQueue<LinkedList>(); | ||
@@ -220,18 +23,16 @@ let deferScheduled = false; | ||
if (!deferScheduled) { | ||
deferScheduled = true; | ||
defer(runJobs); | ||
} | ||
deferScheduled = true; | ||
}; | ||
const addJob = (callback: () => void, priority: number) => { | ||
const getJob = heapJobs.get(priority); | ||
let newLinkedList; | ||
let job = heapJobs.get(priority); | ||
if (!getJob) { | ||
newLinkedList = new LinkedList(); | ||
heapJobs.add(priority, newLinkedList); | ||
if (!job) { | ||
job = new LinkedList(); | ||
heapJobs.add(priority, job); | ||
} | ||
((getJob || newLinkedList) as LinkedList).push(callback); | ||
job.push(callback); | ||
}; | ||
@@ -243,10 +44,9 @@ | ||
while (true) { | ||
if (heapJobs.isEmpty() || Date.now() - timeRun > TIME_LIFE_FRAME) { | ||
if (heapJobs.isEmpty() || Date.now() - timeRun > lifeFrame) { | ||
break; | ||
} else { | ||
const jobs = heapJobs.peek(); | ||
const job = jobs.shift(); | ||
try { | ||
job(); | ||
(jobs.shift())(); | ||
} catch (e) { | ||
@@ -271,3 +71,6 @@ console.error(e); // tslint:disable-line | ||
return function scheduling(callback: () => void, { priority = P_NORMAL } = {}) { | ||
return function scheduling( | ||
callback: () => void, | ||
{ priority = P_NORMAL } = {} | ||
) { | ||
addJob(callback, priority); | ||
@@ -279,2 +82,2 @@ | ||
export default frameScheduling(); | ||
export default createFrameScheduling(); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
38263
15
71
11
812