Implement requestAnimationFrame

This commit replaces setTimeout with a working example of requestAnimationFrame. Some further testing will have to be done
This commit is contained in:
Victor Westerlund 2021-12-05 22:05:30 +01:00
parent fc25c3ccba
commit 7ca095a0d7
3 changed files with 34 additions and 40 deletions

View file

@ -37,11 +37,7 @@ export default class Monkeydo extends MonkeyMaster {
async play(manifest = null) { async play(manifest = null) {
if(!this.ready && !manifest) throw new Error("Can not start playback without a manifest"); if(!this.ready && !manifest) throw new Error("Can not start playback without a manifest");
if(manifest) { if(manifest) await this.load(manifest);
const load = this.load(manifest)
load.then(() => this.start());
return;
}
return await this.start(); return await this.start();
} }
} }

View file

@ -5,40 +5,39 @@ importScripts("https://unpkg.com/comlink/dist/umd/comlink.js");
class Monkey { class Monkey {
constructor() { constructor() {
this.flags = new Uint8ClampedArray(3); this.flags = new Uint8ClampedArray(3);
this.tasks = [];
this.tasksLength = 0; this.tasks = {
this.i = 0; tasks: [],
// Runtime task queue length: 0,
this.queue = { target: 0,
thisTask: null, _i: 0,
nextTask: null set manifest(manifest) {
this.tasks = manifest;
this.length = this.tasks.length - 1;
},
get task() {
return this.tasks[this._i];
},
step: () => {
this.tasks._i++;
const nextTask = this.tasks.task;
this.tasks.target = performance.now() + nextTask[0];
}
} }
} }
// Task scheduler // Main event loop, runs on every frame
next() { tick() {
const start = performance.now(); if(this === undefined) return false;
const self = this; if(this.flags[0] === 0 || this.flags[2] === 0) return this.abort();
let task = null;
// Run task after delay const frame = Math.min(performance.now(),this.tasks.target);
function frame() { if(frame == this.tasks.target) {
if(self.flags[0] === 0 || self.flags[2] === 0) return self.abort(); postMessage(["TASK",this.tasks.task]);
postMessage(["TASK",task]); this.tasks.step();
self.i++;
scheduleFrame();
} }
// Queue the next task requestAnimationFrame(this.tick.bind(this));
function scheduleFrame() {
task = self.tasks[self.i];
//const elapsed = Math.round(performance.now() - start);
const wait = task[0] + start;
console.log(wait);
setTimeout(() => requestAnimationFrame(frame),wait);
}
scheduleFrame(start);
} }
abort() { abort() {
@ -73,9 +72,7 @@ class Monkey {
reject("Failed to load manifest"); reject("Failed to load manifest");
} }
} }
this.tasks = manifest.tasks; this.tasks.manifest = manifest.tasks;
// Store length as property so we don't have to calculate the offset each iteration of next()
this.tasksLength = manifest.tasks.length - 1;
this.flags[0] = 1; // Manifest loaded: true this.flags[0] = 1; // Manifest loaded: true
resolve(); resolve();
}); });

View file

@ -47,11 +47,12 @@ export default class MonkeyMaster {
const Monkey = Comlink.wrap(worker); const Monkey = Comlink.wrap(worker);
this.comlink = await new Monkey(); this.comlink = await new Monkey();
// Wait for comlink to initialize proxy and send queued flags // Wait for comlink to spin up
return await new Promise((resolve,reject) => { return await new Promise((resolve,reject) => {
if(!this.comlink) reject("Failed to open proxy to worker"); if(!this.comlink) reject("Failed to establish Comlink with worker");
this.ready = true; this.ready = true;
// Send queued flags when worker is ready
this.queue.sendAllFlags(); this.queue.sendAllFlags();
resolve(); resolve();
}); });
@ -132,6 +133,6 @@ export default class MonkeyMaster {
if(playing > 0) return; if(playing > 0) return;
await this.setFlag("playing",loop); await this.setFlag("playing",loop);
return await this.comlink.next(); return await this.comlink.tick();
} }
} }