natron-core

Tasks with Promises

Version Downloads Build Status

Creating Tasks

Tasks can be created using the task(thing: Thing, meta: Object) function. A Thing is a Task or anything that can be converted to a task, like Function, Array<Thing>, Set<Thing> or string. Additionally this function can take meta information that will be added to the task, e.g. a name.

import {task} from "natron-core";

let myTask = task(() => {
  return 42;
}, {name: "answer"});

Examples:

  • task(function () {})
  • task(() => {}, {name: "func"})
  • task([a, b, c]) ... a task sequence, where a, b and c are of type Thing
  • task([[x, y, z]]) ... an array, as the only element, inside an array will result in a task set
  • task([a, [[x, y]], b]) ... a -> (x || y) -> b
  • task("func") ... a lazy task, see Task Resolver for more information

Running Tasks

A Task can be executed by calling the run(...args: any) method on the task object which always returns a Promise. The parameters will be passed to the encapsulated function within the task.

let greetTask = task((name) => {
  return `Hello ${name}`;
});

greetTask.run("World").then((val) => {
  console.log(val);
});

Another way to run a task is to use the runWithContext(c: TaskContext) method which expects either a valid TaskContext or an Object. This method allows a more fine-grained execution, see Task Context for more information.

greetTask.runWithContext({args: ["World"]});

Sequence

task([a, b, c, ...]): a -> b -> c

Tasks will be run in sequence

import {task} from "natron-core";

function fn1(x) { return x * 1; }
function fn2(x) { return x * 2; }
function fn3(x) { return x * 3; }

// fn1(2) -> fn2(2) -> fn3(2)
(task([fn1, fn2, fn3]).run(2)
  .then((res) => {
    // res = [2, 4, 6]
  })
  .catch((err) => {
    // handle error
  })
);

Options

pipe

import {task} from "natron-core";

function fn(v) { return `<${v}>`; }

// => fn(".") => fn("<.>") => fn("<<.>>")
(task([fn, fn, fn], {
  options: {pipe: true},
}).run(".")
  .then((res) => {
    // res = "<<<.>>>"
  })
  .catch((err) => {
    // handle error
  })
);

Set

task([[a, b, c, ...]]): a || b || c

Tasks will be run in parallel

import {task} from "natron-core";

function fn1(x) { return x * 1; }
function fn2(x) { return x * 2; }
function fn3(x) { return x * 3; }

// fn1(2) || fn2(2) || fn3(2)
(task([[fn1, fn2, fn3]]).run(2)
  .then((res) => {
    // res = [2, 4, 6]
  })
  .catch((err) => {
    // handle error
  })
);

Compose Complex Tasks

import {task} from "natron-core";

function fn1(x) { return x * 1; }
function fn2(x) { return x * 2; }
function fn3(x) { return x * 3; }

// => fn1(2) -> (fn2(2) || fn3(2))
(task([fn1, [[fn2, fn3]]]).run(2)
  .then((res) => {
    // res = [2, [4, 6]]
  })
  .catch((err) => {
    // handle error
  })
);

Lazy Tasks

import {task} from "natron-core";

function answer() {
  return 4;
}

let store = {
  answer: () => {
    return 42;
  },
};

let myTask = task([answer, "answer"], {
  resolver: (name) => {
    return store[name];
  },
});

myTask.run().then((val) => {
  // val = [4, 42]
});

Event Aggregator

import {EventEmitter} from "events";
import {task} from "natron-core";

let ee = new EventEmitter();

ee.on("start", (e) => {
  // e = {task, context}
});

ee.on("finish", (e) => {
  // e = {task, context, value}
});

ee.on("error", (e) => {
  // e = {task, context, error}
});

(task(/* ... */).runWithContext({
  args: [/* ... */],
  eventAggregator: ee,
})
  .then((res) => {
    // ...
  })
);