Socket
Socket
Sign inDemoInstall

effection

Package Overview
Dependencies
Maintainers
1
Versions
299
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

effection - npm Package Compare versions

Comparing version 0.2.0 to 0.3.0-042fa24

20

CHANGELOG.md

@@ -9,2 +9,22 @@ # Changelog

## [0.3.0] - 2019-10-18
- unify the fork() and execute() methods. There is now a single API
for initiating asynchronous execution, fork() which makes the mental
model much simpler and the learning curve smaller.
https://github.com/thefrontside/effection.js/pull/14
- make the fork() function static. Prior to this, `fork()` was a
method on the `Execution` class which made the API awkward and
non-functional.
https://github.com/thefrontside/effection.js/pull/12
- make generators (not just generator functions) valid
operations. Before this change, you needed to use a utility function
`call()` in order to pass arguments to generator based
operations. This lets you invoke generator functions directly and
pass the resulting generator to `yield` and `fork` directly thus
simplifying code greatly.
https://github.com/thefrontside/effection.js/pull/13
## [0.2.0] - 2019-10-17

@@ -11,0 +31,0 @@

137

dist-node/index.js

@@ -6,2 +6,18 @@ 'use strict';

/**
* Create an execution controller that resumes after the specified
* duration. E.g.
*
* function* waitAndSayHello(target) {
* yield timeout(100);
* console.log(`Hello ${target}!`);
* }
*/
function timeout(durationMillis = 0) {
return function (execution) {
let timeoutId = setTimeout(() => execution.resume(), durationMillis);
return () => clearTimeout(timeoutId);
};
}
/**
* An execution controller that resumes or throws based

@@ -20,2 +36,3 @@ * on a promise.

// what happened to the promise, so make the callbacks noops.
// this effectively "unsubscribes" to the promise.

@@ -31,2 +48,5 @@ return () => succeed = fail = noop;

}
function isGenerator(value) {
return value != null && typeof value.next === 'function' && typeof value.throw === 'function' && typeof value.return === 'function';
}

@@ -47,2 +67,4 @@ function fromConstant(value) {

return value;
} else if (isGenerator(value)) {
return () => value;
} else if (typeof value === 'function') {

@@ -129,6 +151,12 @@ return fromFunction(value);

class Execution {
static of(proc) {
return new Execution(proc, x => x);
static of(operation) {
return new Execution(operation, x => x);
}
static start(operation) {
let execution = Execution.of(operation);
execution.start();
return execution;
}
get isUnstarted() {

@@ -170,4 +198,4 @@ return this.status instanceof Unstarted;

constructor(proc) {
this.proc = toGeneratorFunction(proc);
constructor(operation) {
this.operation = toGeneratorFunction(operation);
this.status = new Unstarted(this);

@@ -178,4 +206,4 @@ this.children = [];

start(args) {
return this.status.start(args);
start() {
return this.status.start();
}

@@ -195,6 +223,2 @@

fork(proc, args) {
return this.status.fork(proc, args);
}
then(...args) {

@@ -238,6 +262,2 @@ this.continuation = this.continuation.then(...args);

fork() {
this.cannot('fork');
}
cannot(operationName) {

@@ -263,6 +283,6 @@ let name = this.constructor.name;

class Unstarted extends Status {
start(args) {
let proc = this.execution.proc;
start() {
let operation = this.execution.operation;
let execution = this.execution;
let iterator = proc.apply(execution, args);
let iterator = operation.apply(execution);
execution.status = new Running(execution, iterator);

@@ -274,2 +294,15 @@ execution.resume();

let currentExecution;
function withCurrentExecution(execution, fn) {
let previousExecution = currentExecution;
try {
currentExecution = execution;
return fn();
} finally {
currentExecution = previousExecution;
}
}
class Running extends Status {

@@ -293,4 +326,6 @@ constructor(execution, iterator, current = {

try {
this.releaseControl();
let next = thunk(iterator);
let next = withCurrentExecution(execution, () => {
this.releaseControl();
return thunk(iterator);
});

@@ -341,14 +376,2 @@ if (next.done) {

fork(task, args) {
let parent = this.execution;
let child = new Execution(task).then(() => {
if (parent.isWaiting && !parent.hasBlockingChildren) {
this.finalize(new Completed(parent, parent.result));
}
}).catch(e => parent.throw(e));
parent.children.push(child);
child.start(args);
return child;
}
}

@@ -402,4 +425,4 @@

function controllerFor(value) {
if (isGeneratorFunction(value)) {
return call(value);
if (isGeneratorFunction(value) || isGenerator(value)) {
return invoke(value);
} else if (typeof value === 'function') {

@@ -416,5 +439,21 @@ return value;

function call(task, ...args) {
function fork(operation) {
if (currentExecution == null) {
return Execution.start(operation);
}
let parent = currentExecution;
let child = new Execution(operation).then(() => {
if (parent.isWaiting && !parent.hasBlockingChildren) {
parent.status.finalize(new Completed(parent, parent.result));
}
}).catch(e => parent.throw(e));
parent.children.push(child);
child.start();
return child;
}
function invoke(operation) {
return parent => {
let child = new Execution(task).then(child => {
let child = new Execution(operation).then(child => {
if (child.isCompleted) {

@@ -433,5 +472,6 @@ return parent.resume(child.result);

parent.children.push(child);
child.start(args);
child.start();
};
}
const ExecutionFinalized = Continuation.of(execution => {

@@ -447,27 +487,4 @@ if (execution.isErrored) {

function execute(task, ...args) {
let execution = Execution.of(task);
execution.start(args);
return execution;
}
/**
* Create an execution controller that resumes after the specified
* duration. E.g.
*
* function* waitAndSayHello(target) {
* yield timeout(100);
* console.log(`Hello ${target}!`);
* }
*/
function timeout(durationMillis = 0) {
return function (execution) {
let timeoutId = setTimeout(() => execution.resume(), durationMillis);
return () => clearTimeout(timeoutId);
};
}
exports.call = call;
exports.execute = execute;
exports.fork = fork;
exports.promiseOf = promiseOf;
exports.timeout = timeout;
import { promiseOf } from "./promise-of.js";
import { isGeneratorFunction, toGeneratorFunction } from "./generator-function.js";
import { isGeneratorFunction, isGenerator, toGeneratorFunction } from "./generator-function.js";
import Continuation from "./continuation.js";
export default class Execution {
static of(proc) {
return new Execution(proc, x => x);
static of(operation) {
return new Execution(operation, x => x);
}
static start(operation) {
let execution = Execution.of(operation);
execution.start();
return execution;
}
get isUnstarted() {

@@ -45,4 +51,4 @@ return this.status instanceof Unstarted;

constructor(proc) {
this.proc = toGeneratorFunction(proc);
constructor(operation) {
this.operation = toGeneratorFunction(operation);
this.status = new Unstarted(this);

@@ -53,4 +59,4 @@ this.children = [];

start(args) {
return this.status.start(args);
start() {
return this.status.start();
}

@@ -70,6 +76,2 @@

fork(proc, args) {
return this.status.fork(proc, args);
}
then(...args) {

@@ -113,6 +115,2 @@ this.continuation = this.continuation.then(...args);

fork() {
this.cannot('fork');
}
cannot(operationName) {

@@ -140,5 +138,5 @@ let name = this.constructor.name;

class Unstarted extends Status {
start(args) {
start() {
let {
proc
operation
} = this.execution;

@@ -148,3 +146,3 @@ let {

} = this;
let iterator = proc.apply(execution, args);
let iterator = operation.apply(execution);
execution.status = new Running(execution, iterator);

@@ -156,2 +154,15 @@ execution.resume();

let currentExecution;
function withCurrentExecution(execution, fn) {
let previousExecution = currentExecution;
try {
currentExecution = execution;
return fn();
} finally {
currentExecution = previousExecution;
}
}
class Running extends Status {

@@ -177,4 +188,6 @@ constructor(execution, iterator, current = {

try {
this.releaseControl();
let next = thunk(iterator);
let next = withCurrentExecution(execution, () => {
this.releaseControl();
return thunk(iterator);
});

@@ -227,14 +240,2 @@ if (next.done) {

fork(task, args) {
let parent = this.execution;
let child = new Execution(task).then(() => {
if (parent.isWaiting && !parent.hasBlockingChildren) {
this.finalize(new Completed(parent, parent.result));
}
}).catch(e => parent.throw(e));
parent.children.push(child);
child.start(args);
return child;
}
}

@@ -292,4 +293,4 @@

function controllerFor(value) {
if (isGeneratorFunction(value)) {
return call(value);
if (isGeneratorFunction(value) || isGenerator(value)) {
return invoke(value);
} else if (typeof value === 'function') {

@@ -306,5 +307,21 @@ return value;

export function call(task, ...args) {
export function fork(operation) {
if (currentExecution == null) {
return Execution.start(operation);
}
let parent = currentExecution;
let child = new Execution(operation).then(() => {
if (parent.isWaiting && !parent.hasBlockingChildren) {
parent.status.finalize(new Completed(parent, parent.result));
}
}).catch(e => parent.throw(e));
parent.children.push(child);
child.start();
return child;
}
function invoke(operation) {
return parent => {
let child = new Execution(task).then(child => {
let child = new Execution(operation).then(child => {
if (child.isCompleted) {

@@ -323,5 +340,6 @@ return parent.resume(child.result);

parent.children.push(child);
child.start(args);
child.start();
};
}
const ExecutionFinalized = Continuation.of(execution => {

@@ -328,0 +346,0 @@ if (execution.isErrored) {

@@ -6,2 +6,5 @@ const GeneratorFunction = function* () {}.constructor;

}
export function isGenerator(value) {
return value != null && typeof value.next === 'function' && typeof value.throw === 'function' && typeof value.return === 'function';
}

@@ -22,2 +25,4 @@ function fromConstant(value) {

return value;
} else if (isGenerator(value)) {
return () => value;
} else if (typeof value === 'function') {

@@ -24,0 +29,0 @@ return fromFunction(value);

@@ -1,4 +0,3 @@

export { execute } from "./execute.js";
export { timeout } from "./timeout.js";
export { call } from "./execution.js";
export { fork } from "./execution.js";
export { promiseOf } from "./promise-of.js";

@@ -15,2 +15,3 @@ /**

// what happened to the promise, so make the callbacks noops.
// this effectively "unsubscribes" to the promise.

@@ -17,0 +18,0 @@ return () => succeed = fail = noop;

/**
* Create an execution controller that resumes after the specified
* duration. E.g.
*
* function* waitAndSayHello(target) {
* yield timeout(100);
* console.log(`Hello ${target}!`);
* }
*/
function timeout() {
let durationMillis = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
return function (execution) {
let timeoutId = setTimeout(() => execution.resume(), durationMillis);
return () => clearTimeout(timeoutId);
};
}
/**
* An execution controller that resumes or throws based

@@ -7,10 +24,11 @@ * on a promise.

return function control(execution) {
var succeed = value => execution.resume(value);
let succeed = value => execution.resume(value);
var fail = err => execution.throw(err);
let fail = err => execution.throw(err);
var noop = x => x;
let noop = x => x;
promise.then(value => succeed(value)).catch(error => fail(error)); // this execution has passed out of scope, so we don't care
// what happened to the promise, so make the callbacks noops.
// this effectively "unsubscribes" to the promise.

@@ -21,3 +39,3 @@ return () => succeed = fail = noop;

var GeneratorFunction = function* () {}.constructor;
const GeneratorFunction = function* () {}.constructor;

@@ -27,2 +45,5 @@ function isGeneratorFunction(fn) {

}
function isGenerator(value) {
return value != null && typeof value.next === 'function' && typeof value.throw === 'function' && typeof value.return === 'function';
}

@@ -47,2 +68,4 @@ function fromConstant(value) {

return value;
} else if (isGenerator(value)) {
return () => value;
} else if (typeof value === 'function') {

@@ -86,3 +109,3 @@ return fromFunction(value);

return flatMap(this, call => Continuation.of(x => {
var next = fn(call(x));
let next = fn(call(x));

@@ -120,3 +143,3 @@ if (next instanceof Continuation) {

function flatMap(continuation, sequence) {
var next = sequence(continuation.call);
let next = sequence(continuation.call);

@@ -131,6 +154,12 @@ if (!(next instanceof Continuation)) {

class Execution {
static of(proc) {
return new Execution(proc, x => x);
static of(operation) {
return new Execution(operation, x => x);
}
static start(operation) {
let execution = Execution.of(operation);
execution.start();
return execution;
}
get isUnstarted() {

@@ -172,4 +201,4 @@ return this.status instanceof Unstarted;

constructor(proc) {
this.proc = toGeneratorFunction(proc);
constructor(operation) {
this.operation = toGeneratorFunction(operation);
this.status = new Unstarted(this);

@@ -180,4 +209,4 @@ this.children = [];

start(args) {
return this.status.start(args);
start() {
return this.status.start();
}

@@ -197,6 +226,2 @@

fork(proc, args) {
return this.status.fork(proc, args);
}
then() {

@@ -240,9 +265,5 @@ this.continuation = this.continuation.then(...arguments);

fork() {
this.cannot('fork');
}
cannot(operationName) {
var name = this.constructor.name;
var message = "tried to perfom operation ".concat(operationName, "() on an execution with status '").concat(name, "'");
let name = this.constructor.name;
let message = "tried to perfom operation ".concat(operationName, "() on an execution with status '").concat(name, "'");
throw new Error("InvalidOperationError: ".concat(message));

@@ -252,5 +273,3 @@ }

finalize(status) {
var {
execution
} = this;
let execution = this.execution;
execution.status = status;

@@ -262,3 +281,3 @@ execution.continuation.call(execution);

var Finalized = Status => class FinalizedStatus extends Status {
const Finalized = Status => class FinalizedStatus extends Status {
halt() {}

@@ -269,10 +288,6 @@

class Unstarted extends Status {
start(args) {
var {
proc
} = this.execution;
var {
execution
} = this;
var iterator = proc.apply(execution, args);
start() {
let operation = this.execution.operation;
let execution = this.execution;
let iterator = operation.apply(execution);
execution.status = new Running(execution, iterator);

@@ -284,5 +299,18 @@ execution.resume();

let currentExecution;
function withCurrentExecution(execution, fn) {
let previousExecution = currentExecution;
try {
currentExecution = execution;
return fn();
} finally {
currentExecution = previousExecution;
}
}
class Running extends Status {
constructor(execution, iterator) {
var current = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
let current = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
done: false

@@ -300,10 +328,10 @@ };

thunk(thunk) {
var {
execution,
iterator
} = this;
let execution = this.execution,
iterator = this.iterator;
try {
this.releaseControl();
var next = thunk(iterator);
let next = withCurrentExecution(execution, () => {
this.releaseControl();
return thunk(iterator);
});

@@ -317,4 +345,4 @@ if (next.done) {

} else {
var control = controllerFor(next.value);
var release = control(execution);
let control = controllerFor(next.value);
let release = control(execution);

@@ -344,6 +372,4 @@ if (typeof release === 'function') {

halt(value) {
var {
execution,
iterator
} = this;
let execution = this.execution,
iterator = this.iterator;
this.releaseControl();

@@ -358,14 +384,2 @@ iterator.return(value);

fork(task, args) {
var parent = this.execution;
var child = new Execution(task).then(() => {
if (parent.isWaiting && !parent.hasBlockingChildren) {
this.finalize(new Completed(parent, parent.result));
}
}).catch(e => parent.throw(e));
parent.children.push(child);
child.start(args);
return child;
}
}

@@ -399,5 +413,3 @@

halt(value) {
var {
execution
} = this;
let execution = this.execution;
execution.status = new Halted(execution, value);

@@ -411,5 +423,3 @@ execution.children.forEach(child => {

throw(error) {
var {
execution
} = this;
let execution = this.execution;
execution.status = new Errored(execution, error);

@@ -425,4 +435,4 @@ execution.children.forEach(child => {

function controllerFor(value) {
if (isGeneratorFunction(value)) {
return call(value);
if (isGeneratorFunction(value) || isGenerator(value)) {
return invoke(value);
} else if (typeof value === 'function') {

@@ -439,9 +449,21 @@ return value;

function call(task) {
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
function fork(operation) {
if (currentExecution == null) {
return Execution.start(operation);
}
let parent = currentExecution;
let child = new Execution(operation).then(() => {
if (parent.isWaiting && !parent.hasBlockingChildren) {
parent.status.finalize(new Completed(parent, parent.result));
}
}).catch(e => parent.throw(e));
parent.children.push(child);
child.start();
return child;
}
function invoke(operation) {
return parent => {
var child = new Execution(task).then(child => {
let child = new Execution(operation).then(child => {
if (child.isCompleted) {

@@ -460,8 +482,9 @@ return parent.resume(child.result);

parent.children.push(child);
child.start(args);
child.start();
};
}
var ExecutionFinalized = Continuation.of(execution => {
const ExecutionFinalized = Continuation.of(execution => {
if (execution.isErrored) {
var error = execution.result;
let error = execution.result;
error.execution = execution;

@@ -474,30 +497,2 @@ throw error;

function execute(task) {
var execution = Execution.of(task);
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
execution.start(args);
return execution;
}
/**
* Create an execution controller that resumes after the specified
* duration. E.g.
*
* function* waitAndSayHello(target) {
* yield timeout(100);
* console.log(`Hello ${target}!`);
* }
*/
function timeout() {
var durationMillis = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
return function (execution) {
var timeoutId = setTimeout(() => execution.resume(), durationMillis);
return () => clearTimeout(timeoutId);
};
}
export { call, execute, promiseOf, timeout };
export { fork, promiseOf, timeout };
declare module "effection" {
export type Operation = SequenceFn | Promise<any> | Controller | undefined;
export type SequenceFn = (this: Execution, ...args: any[]) => Sequence;
export type Sequence = Generator<Operation, any, any>;
export type Operation = SequenceFn | Sequence | Promise<any> | Controller | undefined;
export type SequenceFn = (this: Execution) => Sequence;
export type Controller = (execution: Execution) => void | (() => void);
export interface Sequence extends Generator<Operation, any, any> {}
export interface Execution<T = any> {

@@ -12,6 +13,5 @@ resume(result: T): void;

export function execute<T>(operation: Operation): Execution<T>;
export function call(operation: Operation, ...args: any[]): Operation;
export function fork<T>(operation: Operation): Execution<T>;
export function timeout(durationMillis: number): Operation;
}
{
"name": "effection",
"description": "Effortlessly composable structured concurrency primitive for JavaScript",
"version": "0.2.0",
"version": "0.3.0-042fa24",
"license": "MIT",

@@ -19,3 +19,2 @@ "files": [

"devDependencies": {
"nyc": "13.1.0",
"@babel/core": "7.4.4",

@@ -36,4 +35,3 @@ "@babel/preset-env": "7.4.4",

"mocha": "6.1.4",
"ts-expect": "^1.1.0",
"ts-node": "^8.1.0",
"nyc": "~14.1.1",
"typescript": "^3.6.4"

@@ -40,0 +38,0 @@ },

@@ -68,3 +68,3 @@ [![npm](https://img.shields.io/npm/v/effection.svg)](https://www.npmjs.com/package/effection)

The process primitive is the `Execution`. To create (and start) an
`Execution`, use the `execute` function and pass it a generator. This
`Execution`, use the `fork` function and pass it a generator. This
simplest example waits for 1 second, then prints out "hello world" to

@@ -74,5 +74,5 @@ the console.

``` javascript
import { execute, timeout } from 'effection';
import { fork, timeout } from 'effection';
let process = execute(function*() {
let process = fork(function*() {
yield timeout(1000);

@@ -92,3 +92,3 @@ return 'hello world';

``` javascript
execute(function*() {
fork(function*() {
yield function*() {

@@ -106,3 +106,3 @@ for (let i = 0; i < 10; i++) {

``` javascript
let process = execute(function*() {
let process = fork(function*() {
return yield function*() {

@@ -121,8 +121,7 @@ return yield function*() {

In order to abstract a process so that it can take arguments, you can
use the `call` function:
You can pass arguments to an operation by invoking it.
``` javascript
import { execute, timeout, call } from 'effection';
import { fork, timeout } from 'effection';

@@ -133,22 +132,8 @@ function* waitForSeconds(durationSeconds) {

execute(function*() {
yield call(waitforseconds, 10);
});
fork(waitforseconds(10));
```
More likely though, you would want to define a higher-order function
that took your argument and returned a generator:
``` javascript
function waitForSeconds(durationSeconds) {
return function*() {
yield timeout(durationSeconds * 1000);
}
}
```
### Asynchronous Execution
Sometimes you want to execute some processes in parallel and not
Sometimes you want to fork some processes in parallel and not
necessarily block further execution on them. You still want the

@@ -161,7 +146,7 @@ guarantees associated with structured concurrency however. For

``` javascript
import { execute } from 'effection';
import { fork } from 'effection';
execute(function*() {
this.fork(createFileServer);
this.fork(createHttpServer);
fork(function*() {
fork(createFileServer);
fork(createHttpServer);
});

@@ -168,0 +153,0 @@ ```

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc