avocado-old/packages/behavior/item/actions.js

110 lines
2.4 KiB
JavaScript
Raw Normal View History

2019-04-28 23:45:03 -05:00
import {compose, EventEmitter, TickingPromise} from '@avocado/core';
2019-03-17 23:45:48 -05:00
import {Traversal} from './traversal';
import {Traversals} from './traversals';
2019-04-08 17:41:20 -05:00
const decorate = compose(
EventEmitter,
);
export class Actions extends decorate(Traversals) {
2019-03-17 23:45:48 -05:00
2019-05-05 04:26:35 -05:00
static type() {
return 'actions';
}
2019-03-17 23:45:48 -05:00
constructor() {
super();
2019-04-07 12:00:11 -05:00
this._index = 0;
2019-09-08 19:50:39 -05:00
this._actionPromise = null;
2019-03-17 23:45:48 -05:00
}
2019-04-23 00:30:44 -05:00
emitFinished() {
this.emit('actionsFinished');
2019-04-20 16:02:52 -05:00
}
2019-03-17 23:45:48 -05:00
get index() {
2019-04-07 12:00:11 -05:00
return this._index;
2019-03-17 23:45:48 -05:00
}
set index(index) {
2019-04-07 12:00:11 -05:00
this._index = index;
2019-03-17 23:45:48 -05:00
}
2019-06-06 00:09:51 -05:00
get() {
return this;
}
2019-03-17 23:45:48 -05:00
tick(context, elapsed) {
2019-09-08 19:50:39 -05:00
// Empty resolves immediately.
2019-03-17 23:45:48 -05:00
if (this.traversals.length === 0) {
2019-04-23 00:30:44 -05:00
this.emitFinished();
2019-03-17 23:45:48 -05:00
return;
}
2019-09-08 19:50:39 -05:00
// If the action promise ticks, tick it.
if (this._actionPromise && this._actionPromise instanceof TickingPromise) {
this._actionPromise.tick(elapsed);
2019-03-17 23:45:48 -05:00
return;
}
// Actions execute immediately until a promise is made, or they're all
// executed.
while (true) {
2019-09-08 19:50:39 -05:00
// Run the action.
2019-03-17 23:45:48 -05:00
const result = this.traversals[this.index].traverse(context);
2019-09-08 19:50:39 -05:00
// Deferred result.
2019-03-17 23:45:48 -05:00
if (result instanceof Promise) {
2019-09-08 19:50:39 -05:00
this._actionPromise = result;
// Handle any errors.
result.catch(console.error);
result.finally(() => {
2019-09-08 19:50:39 -05:00
// Finally, run the prologue.
this.prologue();
});
2019-03-17 23:45:48 -05:00
break;
}
2019-09-08 19:50:39 -05:00
// Immediate result.
2019-03-17 23:45:48 -05:00
this.prologue();
2019-09-08 19:50:39 -05:00
// Need to break out immediately if required.
2019-03-17 23:45:48 -05:00
if (0 === this.index) {
break;
}
}
}
2019-06-06 00:09:51 -05:00
parallel(context) {
2019-09-08 19:50:39 -05:00
// Map all traversals to results.
2019-09-08 08:29:31 -05:00
const results = this.traversals.map((traversal) => {
2019-09-08 19:31:14 -05:00
return traversal.traverse(context);
2019-09-08 08:29:31 -05:00
});
2019-09-08 19:50:39 -05:00
// Wrap all results in a TickingPromise.
2019-09-08 19:31:14 -05:00
return TickingPromise.all(results);
2019-06-06 00:09:51 -05:00
}
2019-03-17 23:45:48 -05:00
prologue() {
2019-09-08 19:50:39 -05:00
// Clear out the action promise.
this._actionPromise = null;
// Increment and wrap the index.
this.index = (this.index + 1) % this.traversals.length;
// If rolled over, the actions are finished.
if (0 === this.index) {
2019-04-23 00:30:44 -05:00
this.emitFinished();
2019-03-17 23:45:48 -05:00
}
}
2019-06-07 00:14:16 -05:00
serial(context) {
2019-09-08 19:31:14 -05:00
return this.tickingPromise(context);
2019-06-07 00:14:16 -05:00
}
2019-09-08 07:39:55 -05:00
tickingPromise(context) {
return new TickingPromise(
(resolve) => {
2019-09-08 19:50:39 -05:00
this.once('actionsFinished', resolve);
2019-09-08 07:39:55 -05:00
},
(elapsed) => {
this.tick(context, elapsed);
},
);
}
2019-03-17 23:45:48 -05:00
}