avocado-old/packages/behavior/actions.js
2020-06-23 11:19:59 -05:00

105 lines
2.3 KiB
JavaScript

import {compose, EventEmitter, TickingPromise} from '@avocado/core';
const decorate = compose(
EventEmitter,
);
class Actions {
constructor(expressions) {
this.expressions = 'function' === typeof expressions ? expressions() : expressions;
this._index = 0;
this.promise = null;
}
emitFinished() {
this.emit('actionsFinished');
}
get index() {
return this._index;
}
set index(index) {
this._index = index;
}
get() {
return this;
}
tick(context, elapsed) {
// Empty resolves immediately.
if (this.expressions.length === 0) {
this.emitFinished();
return;
}
// If the action promise ticks, tick it.
if (this.promise && this.promise instanceof TickingPromise) {
this.promise.tick(elapsed);
return;
}
// Actions execute immediately until a promise is made, or they're all
// executed.
while (true) {
// Run the action.
const result = this.expressions[this.index](context);
// Deferred result.
if (result instanceof Promise) {
this.promise = result;
this.promise.catch(console.error).finally(() => this.prologue());
break;
}
// Immediate result.
this.prologue();
// Need to break out immediately if required.
if (0 === this.index) {
break;
}
}
}
parallel(context) {
const results = this.expressions.map((expression) => expression(context));
for (let i = 0; i < results.length; i++) {
const result = results[i];
if (result instanceof TickingPromise) {
return TickingPromise.all(results);
}
if (result instanceof Promise) {
return Promise.all(results);
}
}
return results;
}
prologue() {
// Clear out the action promise.
this.promise = null;
// Increment and wrap the index.
this.index = (this.index + 1) % this.expressions.length;
// If rolled over, the actions are finished.
if (0 === this.index) {
this.emitFinished();
}
}
serial(context) {
return this.tickingPromise(context);
}
tickingPromise(context) {
return new TickingPromise(
(resolve) => {
this.once('actionsFinished', resolve);
},
(elapsed) => {
this.tick(context, elapsed);
},
);
}
}
export default decorate(Actions);