import {compose, EventEmitter, TickingPromise} from '@avocado/core'; import {Traversal} from './traversal'; import {Traversals} from './traversals'; const decorate = compose( EventEmitter, ); export class Actions extends decorate(Traversals) { static type() { return 'actions'; } constructor() { super(); this._index = 0; this.pending = null; } emitFinished() { this.emit('actionsFinished'); } get index() { return this._index; } set index(index) { this._index = index; } get() { return this; } tick(context, elapsed) { if (this.traversals.length === 0) { this.emitFinished(); return; } if (this.pending) { if ( this.pending instanceof TickingPromise && 'function' === typeof this.pending.ticker ) { this.pending.ticker(elapsed); } return; } // Actions execute immediately until a promise is made, or they're all // executed. while (true) { const result = this.traversals[this.index].traverse(context); if (result instanceof Promise) { result.then(() => { this.prologue(); }); result.catch((error) => { console.error(error); this.prologue(); }); this.pending = result; break; } this.prologue(); if (0 === this.index) { break; } } } parallel(context) { const promises = []; const results = []; const tickingPromises = []; for (let i = 0; i < this.traversals.length; i++) { const traversal = this.traversals[i]; const result = traversal.traverse(context); results.push(result); if (result instanceof TickingPromise) { tickingPromises.push(result); } else if (result instanceof Promise) { promises.push(result); } } if (tickingPromises.length > 0) { const tickingPromise = new TickingPromise((resolve) => { resolve(Promise.all(results)); }); tickingPromise.ticker = (elapsed) => { for (let i = 0; i < tickingPromises.length; i++) { tickingPromises[i].ticker(elapsed); } }; return tickingPromise; } if (promises.length > 0) { return Promise.all(results); } return results; } prologue() { this.pending = null; if (0 === (this.index = (this.index + 1) % this.traversals.length)) { this.emitFinished(); } } }