2019-10-25 15:45:56 +02:00
|
|
|
import { Fiber } from "./fiber";
|
2020-04-17 12:12:02 +02:00
|
|
|
import { browser } from "../browser";
|
2019-10-25 15:45:56 +02:00
|
|
|
|
2019-10-24 21:20:52 +02:00
|
|
|
/**
|
|
|
|
|
* Owl Scheduler Class
|
|
|
|
|
*
|
|
|
|
|
* The scheduler is the part of Owl that will effectively apply a rendering
|
|
|
|
|
* whenever a fiber is ready.
|
|
|
|
|
*
|
|
|
|
|
* Briefly, it can be used to register root fibers. Whenever there is an
|
|
|
|
|
* active root fiber, it will poll continuously each animation frame (so, about
|
|
|
|
|
* once every 16ms) and whenever a root fiber is ready, it will apply it.
|
|
|
|
|
*/
|
|
|
|
|
|
2019-10-25 15:45:56 +02:00
|
|
|
interface Task {
|
|
|
|
|
fiber: Fiber;
|
2019-10-26 16:44:12 +02:00
|
|
|
callback: (err?: Error) => void;
|
2019-10-25 15:45:56 +02:00
|
|
|
}
|
|
|
|
|
|
2019-10-24 21:20:52 +02:00
|
|
|
export class Scheduler {
|
|
|
|
|
tasks: Task[] = [];
|
|
|
|
|
isRunning: boolean = false;
|
2020-04-17 12:12:02 +02:00
|
|
|
requestAnimationFrame: Window["requestAnimationFrame"];
|
2019-10-24 21:20:52 +02:00
|
|
|
|
2020-04-17 12:12:02 +02:00
|
|
|
constructor(requestAnimationFrame: Window["requestAnimationFrame"]) {
|
2019-10-24 21:20:52 +02:00
|
|
|
this.requestAnimationFrame = requestAnimationFrame;
|
|
|
|
|
}
|
2019-10-25 15:45:56 +02:00
|
|
|
|
2019-12-02 17:13:12 +01:00
|
|
|
start() {
|
|
|
|
|
this.isRunning = true;
|
|
|
|
|
this.scheduleTasks();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stop() {
|
|
|
|
|
this.isRunning = false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-16 09:46:47 +01:00
|
|
|
addFiber(fiber: Fiber): Promise<void> {
|
2019-11-21 11:23:05 +01:00
|
|
|
// if the fiber was remapped into a larger rendering fiber, it may not be a
|
|
|
|
|
// root fiber. But we only want to register root fibers
|
|
|
|
|
fiber = fiber.root;
|
2019-11-05 14:23:06 +01:00
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
if (fiber.error) {
|
|
|
|
|
return reject(fiber.error);
|
|
|
|
|
}
|
|
|
|
|
this.tasks.push({
|
|
|
|
|
fiber,
|
|
|
|
|
callback: () => {
|
|
|
|
|
if (fiber.error) {
|
2019-11-14 14:09:42 +01:00
|
|
|
return reject(fiber.error);
|
2019-11-05 14:23:06 +01:00
|
|
|
}
|
|
|
|
|
resolve();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
if (!this.isRunning) {
|
2019-12-02 17:13:12 +01:00
|
|
|
this.start();
|
2019-11-05 14:23:06 +01:00
|
|
|
}
|
|
|
|
|
});
|
2019-10-24 21:20:52 +02:00
|
|
|
}
|
|
|
|
|
|
2020-02-16 09:46:47 +01:00
|
|
|
rejectFiber(fiber: Fiber, reason: string) {
|
|
|
|
|
fiber = fiber.root;
|
|
|
|
|
const index = this.tasks.findIndex(t => t.fiber === fiber);
|
|
|
|
|
if (index >= 0) {
|
|
|
|
|
const [task] = this.tasks.splice(index, 1);
|
|
|
|
|
fiber.cancel();
|
|
|
|
|
fiber.error = new Error(reason);
|
|
|
|
|
task.callback();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-24 21:20:52 +02:00
|
|
|
/**
|
|
|
|
|
* Process all current tasks. This only applies to the fibers that are ready.
|
|
|
|
|
* Other tasks are left unchanged.
|
|
|
|
|
*/
|
2019-10-25 15:45:56 +02:00
|
|
|
flush() {
|
|
|
|
|
let tasks = this.tasks;
|
|
|
|
|
this.tasks = [];
|
|
|
|
|
tasks = tasks.filter(task => {
|
2019-11-05 14:23:06 +01:00
|
|
|
if (task.fiber.isCompleted) {
|
|
|
|
|
task.callback();
|
2019-10-25 15:45:56 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (task.fiber.counter === 0) {
|
2019-11-05 14:23:06 +01:00
|
|
|
if (!task.fiber.error) {
|
2019-11-18 14:15:53 +01:00
|
|
|
try {
|
|
|
|
|
task.fiber.complete();
|
|
|
|
|
} catch (e) {
|
|
|
|
|
task.fiber.handleError(e);
|
|
|
|
|
}
|
2019-11-05 14:23:06 +01:00
|
|
|
}
|
|
|
|
|
task.callback();
|
2019-10-25 15:45:56 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
this.tasks = tasks.concat(this.tasks);
|
2019-12-02 17:13:12 +01:00
|
|
|
if (this.tasks.length === 0) {
|
|
|
|
|
this.stop();
|
|
|
|
|
}
|
2019-10-24 21:20:52 +02:00
|
|
|
}
|
2019-10-25 15:45:56 +02:00
|
|
|
|
|
|
|
|
scheduleTasks() {
|
2019-10-24 21:20:52 +02:00
|
|
|
this.requestAnimationFrame(() => {
|
|
|
|
|
this.flush();
|
2019-12-02 17:13:12 +01:00
|
|
|
if (this.isRunning) {
|
2019-10-24 21:20:52 +02:00
|
|
|
this.scheduleTasks();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-10-30 11:35:28 +01:00
|
|
|
|
2020-04-17 12:12:02 +02:00
|
|
|
export const scheduler = new Scheduler(browser.requestAnimationFrame);
|