Giter VIP home page Giter VIP logo

use-tasker's Introduction

useTasker

A React Hook to schedule asynchronous things.

Install

yarn add use-tasker

Usage

Import the repo and try out the example in CodeSandbox:

https://codesandbox.io/s/github/boopathi/use-tasker

Example:

import { useTasker, seq, concurrent, task } from "use-tasker";

const sleep = (t) => new Promise((r) => setTimeout(r, t));

function Pipeline() {
  const { state, start } = useTasker(
    seq(
      "pipeline",
      task("title 1", async () => {
        await sleep(2000);
      }),
      concurrent(
        "deploy",
        task("deploy pods", async () => {
          await sleep(3000);
        }),
        task("deploy service", async () => {
          await sleep(3000);
        }),
        task("deploy ingress", async () => {
          await sleep(3000);
        })
      )
    )
  );

  return (
    <div>
      <pre>
        <code>{JSON.stringify(state, null, 2)}</code>
      </pre>
    </div>
  );
}

API

useTasker

const { state, start } = useTasker(taskList, context);
  • taskList: TaskList - The TaskList returned by seq or concurrent functions described below
  • context: any - The parameter passed to all taskFn functions. You can use this as an internal state to pass values from one task to another.
  • returns { state, start }
  • state: TaskerState - A nested structure that is updated as the tasks complete. This is the store of a reducer. More details under state topic.
  • start: () => void - The function to start running the tasks. Add this as the click event handler of a button or a similar other thing.

state

The state returned by the useTasker hook gives the current state of the execution pipeline. It's a nested recursive structure that is derived from the input structure of the taskList.

The type definition of the state can be imported for TS projects and is defined as -

type TaskRunStatus = "NOT_STARTED" | "LOADING" | "SUCCESS" | "ERROR";

interface TaskerState {
  title: string;
  status: TaskRunStatus;
  tasks?: TaskerState[];
  error?: any;
}

The state updates as and when the execution proceeds and triggers a re-render of the component that uses useTasker. You can create two mututally recursive components to render this recursive state. For example, the following code will render the recursive state as a nested ul, li list.

import { TaskerState } from "use-tasker";

function ListItem({ data }: { data: TaskerState }) {
  return (
    <li>
      {data.status}: {data.title} ({data.error ? data.error.message : null})
      {data.tasks ? <List tasks={data.tasks} /> : null}
    </li>
  );
}

function List({ tasks }: { tasks: TaskerState["tasks"] }) {
  return (
    <ul>
      {tasks.map((it) => (
        <ListItem data={it} key={it.title + it.status} />
      ))}
    </ul>
  );
}

task

import { task } from "use-tasker";

The task specifier. A task can retur any value including promises. If a task returns, it means it is successfully completed. If the task throws an error or returns a rejected promise, the task failed.

task(name, taskFn);
  • name: string- name of the task
  • taskFn: (context) => any | Promise<any> - the task function
    • context: any - the context passed to useTasker
  • returns Task

seq

import { seq } from "use-tasker";

A sequence TaskList specifier. Members of the sequence are executed sequentially. An Error in one of the steps will stop the execution of the sequence.

seq(name, ...taskLike);
  • name: string- name for the sequence
  • taskLike: Task | TaskList - a Task returned by the task function or another seq or concurrent TaskList returned by seq or concurrent functions
  • returns TaskList

concurrent

import { concurrent } from "use-tasker";

A concurrent TaskList specifier. Members are executed concurrently using Promise.allSettled. An error in one or more of the members will be collected and thrown as a ConcurrentTasksError - more details about this error is described below in Error Handling.

concurrent(name, ...taskLike);
  • name: string- name for the concurrent tasks
  • taskLike: Task | TaskList - a Task returned by the task function or another seq or concurrent TaskList returned by seq or concurrent functions
  • returns TaskList

Error handling

  • task: Tasks can throw an error or return a rejected Promise. Depending on whether it is used as a member of seq or concurrent, the error is handled accordingly.

    task("title1", () => {
      throw new Error("title1");
    });
    task("title2", () => {
      return Promise.reject(new Error("title2"));
    });
  • seq: Errors thrown or rejected promises in seq stop the current pipeline.

  • concurrent: Errors thrown or rejected promises in concurrent are collected as it is collected by Promise.allSettled. They are then wrapped using a custom error class - ConcurrentTasksError. For example,

    import { ConcurrentTasksError } from "use-tasker";
    
    function ErrorComponent(state: TaskerState) {
      if (state.error) {
        if (state.error instanceof ConcurrentTasksError) {
          return <div>{state.error.errors.map((err) => err.message)}</div>;
        }
      }
      return null;
    }

Related

This project is inspired by Listr, which is a terminal task list.

License

MIT

use-tasker's People

Contributors

boopathi avatar

Stargazers

Roman avatar Abhishek Saha avatar  avatar 王洪莹 avatar

Watchers

 avatar James Cloos avatar  avatar

Forkers

19880104

use-tasker's Issues

feature: skip a particular task or entire seq or concurrent tasks list

Feature: Ability to skip a certain tasks on failure

seq(
  "seq title",
  // seq options
  {
    skip(ctx) {}
  },
  task(
    "preliminary things",
    (ctx) => {
      ctx.shouldSkip = true;
    }
  ),
  task(
    "title",
    {
      skip(context) {
        if (context.shouldSkip) return true;
      }
    },
    () => { throw new MyError("title error"); }
  )
)

Both - task(title, taskFn), and task(title, options, taskFn) should work
Similarly - seq(title, options, ...taskLike) and seq(title, ...taskLike should work.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.