// Task scheduler and iterator of Monkeydo manifests class Monkey { constructor(manifest) { this.data = manifest.body; this.dataLength = this.data.length - 1; this.flags = { playing: 0, stacking: 0, // Subsequent calls to play() will build a queue (jQuery-style) loop: 0, // Loop n times; <0 = infinite } this.i = 0; this.queue = { task: null, next: null } Object.seal(this.queue); } // Parse task components and send them to main thread run(data) { this.i++; // Advance index postMessage(data); console.log(this.i); } // Interrupt timeout and put monkey to sleep interrupt() { clearTimeout(this.queue.task); clearTimeout(this.queue.next); this.queue.task = null; this.queue.next = null; this.flags.playing = 0; } play() { if(this.flags.playing) { if(this.flags.stacking) { this.flags.loop++; } return; } this.queueNext(); } // Schedule task for execution by index queueNext() { this.flags.playing = 1; const data = this.data[this.i]; // Schedule the current task to run after the specified wait time this.queue.task = setTimeout(() => this.run(data.do),data.wait); // We're out of tasks to schedule.. if(this.i >= this.dataLength) { this.i = -1; // Exit if we're out of loops if(this.flags.loop === 0) { this.flags.playing = 0; return false; } if(this.flags.loop <= -1) { this.flags.loop = this.flags.loop - 1; } } // Run this function again when the scheduled task will fire this.queue.next = setTimeout(() => this.queueNext(),data.wait); } } // Global message event handler for this worker onmessage = (message) => { const type = message.data[0] ? message.data[0] : message.data; const data = message.data[1]; switch(type) { // Attempt to load manfiest provided by initiator thread case "GIVE_MANIFEST": try { this.monkey = new Monkey(data); postMessage("OK"); } catch(error) { postMessage(["MANIFEST_ERROR",error]); } break; // Set playstate case "SET_PLAYING": if(data === true) { this.monkey.play(); return; } // Treat data that isn't a TRUE boolean as an interrupt this.monkey.interrupt(); break; case "GET_FLAG": const flag = this.monkey.flags[data]; postMessage(parseInt(flag)); break; case "SET_FLAG": console.log(data); this.monkey.flags[data[0]] = data[1]; break; default: return; // No op } }