npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

nv-task-event-tree

v1.0.7

Published

simple bottom-to-up event-tree with pause/continue support

Downloads

11

Readme

nv-task-event-tree

  • nv-task-event-tree
  • simple event tree, bottom-to-up-style
  • support two kind task-nodes: serial AND parallel
  • support recover, pause/continue
  • support 4 ctrl keywords: IF and ELIF and ELSE and WHILE

install

  • npm install nv-task-event-tree

usage

 const evt = require("nv-task-event-tree")

example

load_from_blue_print

    const evt = require("nv-task-event-tree");


    //blue_print is in bottom-to-up style

    var bp = `
       (
            [tsk000]->
            {
                [tsk0010]-|
                [tsk0011]-|
                [tsk0012]-|
            }-> [tsk001]->
            {
                [tsk0020]-|
                [tsk0021]-|
                [tsk0022]-|
            }-> [tsk002]->
       )-> [tsk00]
    `



    /*
     *        {...}        means parallel task, 
                           it will start children at the same time,similiar to Promise.all
     *        (...)        means serial task,   
                           it will start in DFS-sequence, similar to html-traverse sequence
     *        [task-name]  task-name MUST be enclosed in []
     *        ->           means parent task is serial,   is OPTIONAL and JUST a SIGN
     *                     (coz '(...)' already decided)
     *        -|           means parent task is parallel, is OPTIONAL  and JUST a SIGN
     *                     (coz '{...}' already decided)
     *
     */

     /*
      *   大括号括起来的 {child,child....}  表示一个!并行!任务节点: child 是同时开始的
      *   小括号括起来的 (child,child....)  表示一个!串行!任务节点: child 是按照DFS序依次执行的
      *   -|  表示该节点的父节点是 并行节点, -| 是可以省略的,只是为了看起来清楚一些,起决定作用的是 外层的{}
      *   ->  表示该节点的父节点是 串行节点, -> 是可以省略的,只是为了看起来清楚一些,起决定作用的是 外层的()
      *   []  表示任务节点名
      */

        /*
         *  the executing sequence as below(
                   its starting from-top-to-down,
                   and executing from-bottom-to-up
            ):
         *
         *     [tsk000] start->
         *
         *     {[tsk0010],[tsk0011],[tsk0012]}  parallel-start  //coz parent [tsk001] is parallel
         *            [tsk001] will handle notifications        //similiar to Promise.all
         *     [tsk001] start->
         *
         *     {[tsk0020],[tsk0021],[tsk0022]}  parallel-start  //coz parent [tsk001] is parallel
         *            [tsk002] will handle notifications        //similiar to Promise.all
         *     [tsk002] start->
         *
         *     [tsk00] start->
         *                            // [tsk000]->[tsk001]->[tsk002] 
                                      //is executed one-after-one,coz parent [tsk00] is serial
         *
         *     at final,[@root@](created by default) will return a promise, 
               it could be found at tsk.p_ 
         *
         */



        /*
         *  上图表示如下执行顺序(是一个自顶向下开始,但是自底向上执行的模型):
         *
         *     [tsk000] 先开始->
         *
         *     {[tsk0010],[tsk0011],[tsk0012]}  并行开始  //因为父节点[tsk001] 是一个并行节点
         *           结束后通知 [tsk001]                  //行为类似Promise.all
         *     [tsk001] 开始->
         *
         *     {[tsk0020],[tsk0021],[tsk0022]}  并行开始  //因为父节点[tsk002] 是一个并行节点
         *           结束后通知 [tsk002]                  //行为类似Promise.all
         *     [tsk002] 开始->
         *
         *     [tsk00] 开始->
         *          // [tsk000]->[tsk001]->[tsk002] 是按顺序执行的,因为父节点 [tsk00] 是一个串行节点
         *
         *     最后最顶层的[@root@](默认生成的) 
         *     会有一个promise(根节点的一个getter : tsk.p_)
         */


          var tsk = evt.load_from_blue_print(bp)

          //now the task-tree topology is ready
          //现在任务流的 执行树 已经 配置好了

            tsk.show()
            /*
            (
                (
                    [tsk000 : ready]->
                    {
                        [tsk0010 : ready]      -|
                        [tsk0011 : ready]      -|
                        [tsk0012 : ready]      -|
                    }-> [tsk001 : ready]->
                    {
                        [tsk0020 : ready]      -|
                        [tsk0021 : ready]      -|
                        [tsk0022 : ready]      -|
                    }-> [tsk002 : ready]
                )-> [tsk00 : ready : ready]
            )-> [0 : ready]
            */

            //now we need to add executor to task-node
            //    executor is a function :  (rtrn,thrw,self)=> {...}
            //        rtrn IS return/resolve
            //        thrw IS throw/reject 
            //        self IS the-task-node  self provide many methods begin with $
            //             SUCH AS .$parent_  .$fstch_  .$lsib_ .$rsib_...
            //             TO GET RELATIONS, its for simulate SCOPE

            //we create a function-factory for testing, which always rtrn(return/resolve)

             

            //接下来要给节点上添加任务
            //    任务是一个形如  (rtrn,thrw,self)=> {...}  的函数
            //        rtrn 是return
            //        thrw 是throw
            //        self 是任务节点本身 可以通过 提供的很多$开头的方法
            //             比如 .$parent_  .$fstch_  .$lsib_ .$rsib_...
            //             来获取相关的关系, 起到类似定义域查询的功能

            //为了简化,创建一个生成异步任务的函数, 全部是成功


            function creat_executor(delay) {
                let _f = (rtrn,thrw,self)=> {
                    console.log(self.name_,'started at',new Date())
                    setTimeout(
                        ()=> {
                            console.log(self.name_,'succ at',new Date())
                            rtrn(self.name_)
                        },
                        delay
                    )
               }
               return(_f)
            }


            //add executor to task-node
            //   .T_ is a setter Proxy, use tsk.T_.executor_ =  to add executor-func

            //给节点添加任务
            //    .T_ 是一个setter Proxy, 使用它来添加节点任务(.executor_)
            //为了便于观察,延迟设置长一点,比如5秒

            tsk.T_.tsk0020.executor_         = creat_executor(5000)
            tsk.T_.tsk0021.executor_         = creat_executor(5000)
            tsk.T_.tsk0022.executor_         = creat_executor(5000)
                tsk.T_.tsk002.executor_      = creat_executor(5000)
            tsk.T_.tsk0010.executor_         = creat_executor(5000)
            tsk.T_.tsk0011.executor_         = creat_executor(5000)
            tsk.T_.tsk0012.executor_         = creat_executor(5000)
                tsk.T_.tsk001.executor_      = creat_executor(5000)
                tsk.T_.tsk000.executor_      = creat_executor(5000)
                    tsk.T_.tsk00.executor_   = creat_executor(5000)
                       tsk.executor_         = (rtrn,thrw,self) => {  //collect all results on root-node
                            rtrn(self.$sdfs_.map(nd=>nd.rslt_))       //根节点上采集所有任务结果用来观察
                       }


        //launch the task
        //启动任务

        var p = tsk.launch();

        tsk000 started at 2021-12-16T09:31:33.985Z
        tsk000 succ at 2021-12-16T09:31:38.993Z
        tsk0010 started at 2021-12-16T09:31:38.995Z
        tsk0011 started at 2021-12-16T09:31:38.995Z
        tsk0012 started at 2021-12-16T09:31:38.996Z

       
        // when the task-tree is executing USE tsk.show() TO observe the state
        //      if task-nodes too many
        //          do not USE tsk.show(),console will be slow ,coz it will expand the whole tree
        //          should USE tsk.T_[task-name].show(),it only expand the subtree
        //          at the same time USE 
        //               tsk.T_[task-name].$ances_.forEach(pr=>pr.show()),TO observe ancestor-task-nodes

        // 执行过程中使用tsk.show() 观察节点任务执行状态
        //      如果任务节点特别多
        //          不要使用 tsk.show(),console会很卡,因为会展开整棵任务树
        //          应该使用 tsk.T_[task-name].show(),只展开子树
        //          同时使用 tsk.T_[task-name].$ances_.forEach(pr=>pr.show()),来观察 父祖节点状态


        > tsk.show()

mixed-blue-print-state0

        tsk0010 succ at 2021-12-16T09:31:44.000Z
        tsk0011 succ at 2021-12-16T09:31:44.007Z
        tsk0012 succ at 2021-12-16T09:31:44.011Z
        tsk001 started at 2021-12-16T09:31:44.014Z
        tsk001 succ at 2021-12-16T09:31:49.022Z
        tsk0020 started at 2021-12-16T09:31:49.024Z
        tsk0021 started at 2021-12-16T09:31:49.024Z
        tsk0022 started at 2021-12-16T09:31:49.028Z

        > tsk.show()

mixed-blue-print-state1

        tsk0020 succ at 2021-12-16T09:31:54.028Z
        tsk0021 succ at 2021-12-16T09:31:54.034Z
        tsk0022 succ at 2021-12-16T09:31:54.042Z
        tsk002 started at 2021-12-16T09:31:54.044Z
        tsk002 succ at 2021-12-16T09:31:59.046Z
        tsk00 started at 2021-12-16T09:31:59.048Z

mixed-blue-print-state2

        tsk00 succ at 2021-12-16T09:32:04.051Z

        > tsk.show()

mixed-blue-print-state3

        > p         //tsk.p_
        Promise {
          [
            Symbol(noexist), 'tsk00',
            'tsk000',        'tsk001',
            'tsk0010',       'tsk0011',
            'tsk0012',       'tsk002',
            'tsk0020',       'tsk0021',
            'tsk0022'
          ],
          [Symbol(async_id_symbol)]: 44,
          [Symbol(trigger_async_id_symbol)]: 5,
          [Symbol(destroyed)]: { destroyed: false }
        }
        >

reset

soft_reset

     //IF the tsk in a settled-state:
     //    resolved | self_rejected | bubble_rejected | impossible
     //OR ready-state : ready
     //    USE tsk.soft_reset()
 

hard_reset

     //IF the tsk in a pending-state:
     //    opened | self_executing
     //OR in a paused-state:
     //    self_paused | bubble_paused
     //OR in conding-state:            which is USED to support IF/ELIF/ELSE/WHILE
     //    conding
     //USE tsk.hard_reset()      
     //----
     //hard_reset  will respawn many nodes, do NOT use it
     //   coz in JS layer ,you CANT always real pause a executing task,
     //   such as setTimeout USING clearTimeout
     //           fetch      USING AbortController
     //   but NOT all async function has FIXED cancel method  
     //   so  we must replace/respawn the task-node to avoid pollution

pause AND continue

   //since the task-tree settled, we first reset the tsk
   //上面的任务树已经执行完一次了,先调用 tsk.soft_reset() 重置一下
    
    > tsk.soft_reset()
    Task [0 : ready] {}
    >
    > tsk.show()
    (
        (
            [tsk000 : ready]->
            {
                [tsk0010 : ready]-|
                [tsk0011 : ready]-|
                [tsk0012 : ready]-|
            }-> [tsk001 : ready]->
            {
                [tsk0020 : ready]-|
                [tsk0021 : ready]-|
                [tsk0022 : ready]-|
            }-> [tsk002 : ready]
        )-> [tsk00 : ready]
    )-> [0 : ready]

    //we change the executor on [tsk0011] to a larger delay, for observing the pause behavior
    //为了进行pause 的实验,我们把 [tsk0011] 上的 executor 换一个deley 大点的

    tsk.T_.tsk0011.executor_         = creat_executor(60000)
     
    var p = tsk.launch();
    /*
        tsk000 started at 2021-12-16T11:07:11.145Z
        tsk000 succ at 2021-12-16T11:07:16.153Z
        tsk0010 started at 2021-12-16T11:07:16.155Z
        tsk0011 started at 2021-12-16T11:07:16.155Z
        tsk0012 started at 2021-12-16T11:07:16.156Z
        tsk0010 succ at 2021-12-16T11:07:21.158Z
        tsk0012 succ at 2021-12-16T11:07:21.162Z
    */
     
    //now we pause it
    //现在我们暂停它
    > tsk.pause()
       Set(1) { Task [tsk0011 : self_paused] {} }
    >
    > tsk.running_
      Set(1) { Task [tsk0011 : self_paused] {} } 
   
    //running_ is a getter for all-currently self-executing|self-paused task-nodes
    //   it is a Set , for support parallel (maybe multi task-nodes self-executing at the same time)
    //running_ 包含所有 self-executing|self-paused 节点
    //   它是一个Set,目的是为了支持!并行!父节点, 因为在JS层宏观上,同一时刻可能有多个节点在执行
    
    > tsk.show()
     

mixed-blue-print-state4

    !!!!IMPORTANT!!!!
    //let we  wait for enough time, you will notice the below log(since [tsk0011] already paused)
    //我们等待足够长时间,能够看到下面的LOG(虽然[tsk0011]已经paused了) 
         !!!【tsk0011 succ at 2021-12-16T11:08:16.157Z】!!!
    //but just IGNORE it, coz its from the executor-frame-on-old-task-node   
    //since you can NOT  always real pause most function in JS layer(
    //         such as fetch USING AbortController;
    //         setTimeout USING clearTimeout;
    //         but NOT all async API provide  cancel/abort/pause method  
    //)
    //so nv-task-event-tree USE a trick: it replace/respawn  the old-task-node with a-new-one 
    //on the same place in task-tree
    //但是不用担心,忽略它好了
    //它其实是从 旧的[tsk0011] 上的executor-frame来的
    //因为在JS层,多大多数函数来说,并不能真正的暂停,即使提供了类似 cancel/abort/pause功能的
    //    接口也不一致 : setTimeout,AbortController.....
    //所以nv-task-event-tree用了一个技巧: replace/respawn  旧的[tsk0011] 
    //此时虽然节点上的属性 executor conder state 与 旧的[tsk0011] 完全一样,但是是一个新节点
    //    旧的[tsk0011] 上的executor虽然还在执行,但是其结果不会污染 task-node 
    > tsk.show()

mixed-blue-print-state5

    > p
    Promise {
      <pending>,                         // still pending
      [Symbol(async_id_symbol)]: 161,
      [Symbol(trigger_async_id_symbol)]: 5,
      [Symbol(destroyed)]: { destroyed: false }
    }
    >

    //now we continue the task-tree
    //现在我们执行 tsk.continue() 

    > tsk.continue()
    tsk0011 started at 2021-12-16T11:11:37.037Z
    Set(1) { Task [tsk0011 : self_executing] {} }
    

mixed-blue-print-state6

        >
        tsk0011 succ at 2021-12-16T11:12:37.049Z
        tsk001 started at 2021-12-16T11:12:37.050Z
        tsk001 succ at 2021-12-16T11:12:42.051Z
        tsk0020 started at 2021-12-16T11:12:42.052Z
        tsk0021 started at 2021-12-16T11:12:42.053Z
        tsk0022 started at 2021-12-16T11:12:42.054Z
        tsk0020 succ at 2021-12-16T11:12:47.058Z
        tsk0021 succ at 2021-12-16T11:12:47.059Z
        tsk0022 succ at 2021-12-16T11:12:47.060Z
        tsk002 started at 2021-12-16T11:12:47.067Z
        tsk002 succ at 2021-12-16T11:12:52.076Z
        tsk00 started at 2021-12-16T11:12:52.077Z
        tsk00 succ at 2021-12-16T11:12:57.081Z

        > tsk.running_
        Set(0) {}
        >

mixed-blue-print-state7

        //OK .done  reset the task-tree
        tsk.soft_reset();

rejected AND recover

   tsk.soft_reset();

   //we change the executor on [tsk0011] to let it random fail
   //为了进行rejected 的实验,我们把 [tsk0011] 上的 executor 换一个大概率fail 小概率succ的

    tsk.T_.tsk0011.executor_         =  (rtrn,thrw,self) => {
            console.log(self.name_,'started at',new Date())
            setTimeout(
                ()=> {
                    let failed = Math.random() > 0.25;
                    if(failed) {
                        console.log(self.name_,'failed at',new Date())
                        thrw(new Error(self.name_))
                    } else {
                        console.log(self.name_,'succ at',new Date())
                        rtrn(self.name_)
                    }
                },
                delay
            )
    }

    var p = tsk.launch();

    >
    tsk000 started at 2021-12-16T12:09:03.870Z
    tsk000 succ at 2021-12-16T12:09:08.877Z
    tsk0010 started at 2021-12-16T12:09:08.883Z
    tsk0011 started at 2021-12-16T12:09:08.890Z
    tsk0012 started at 2021-12-16T12:09:08.896Z
    tsk0010 succ at 2021-12-16T12:09:13.895Z
    tsk0011 failed at 2021-12-16T12:09:13.898Z
    Uncaught Error: tsk0011                        //----->
    tsk0012 succ at 2021-12-16T12:09:13.918Z
    >

    > tsk
    Task [0 : bubble_rejected] {}


    > tsk.rejected_at_                  //tsk.rejected_at_ is a getter of current-self-rejected node
    Task [tsk0011 : self_rejected] {}
    >

mixed-blue-print-state8

    > p
    Promise {
      <rejected> [Error: tsk0011],
      [Symbol(async_id_symbol)]: 44,
      [Symbol(trigger_async_id_symbol)]: 5,
      [Symbol(destroyed)]: { destroyed: false }
    }
    >

    //now lets try to recover
    //   recover will renew the tsk.p_
    //recover 会产生一个新的promise 
    > var np = tsk.recover()         
    tsk0011 started at 2021-12-16T12:10:13.566Z
    tsk0011 failed at 2021-12-16T12:10:18.569Z
    Uncaught Error: tsk0011
    
    > var np = tsk.recover()                    //---AGAIN
    tsk0011 started at 2021-12-16T12:10:21.757Z
    tsk0011 succ at 2021-12-16T12:10:26.764Z
    tsk001 started at 2021-12-16T12:10:26.765Z
    tsk001 succ at 2021-12-16T12:10:31.773Z
    tsk0020 started at 2021-12-16T12:10:31.775Z
    tsk0021 started at 2021-12-16T12:10:31.776Z
    tsk0022 started at 2021-12-16T12:10:31.782Z
    tsk0020 succ at 2021-12-16T12:10:36.782Z
    tsk0021 succ at 2021-12-16T12:10:36.783Z
    tsk0022 succ at 2021-12-16T12:10:36.787Z
    tsk002 started at 2021-12-16T12:10:36.791Z
    tsk002 succ at 2021-12-16T12:10:41.798Z
    tsk00 started at 2021-12-16T12:10:41.799Z
    tsk00 succ at 2021-12-16T12:10:46.805Z


    > tsk.rejected_at_
    Symbol(noexist)

mixed-blue-print-state9

     tsk.soft_reset();

carryon

  • carryon EQUALS recover() | continue(), based on the stuck-reason

ctrl keywords

  • IF(conder)
  • ELIF(conder)
  • ELSE
  • WHILE(condet)

conder

 conder:(rtrn_tru,rtrn_fls,self) => {...}
 //similar to executor 
 //on each task use .conder_ =   to set it    

if/elif/else

  • if chain only work on children of serial-task-node

    //let us create a simple task-tree: just a serial-link // IF/ELIF/ELSE 只能使用在 串行 父节点的 子节点上

    var bp =([tsk0]->[tsk1]->[tsk2]->[tsk3]->[tsk4]->[tsk5]);

    var tsk = evt.load_from_blue_print(bp)

      /*
      > tsk.show()
      (
          (
              [tsk0 : ready]->
              [tsk1 : ready]->
              [tsk2 : ready]->
              [tsk3 : ready]->
              [tsk4 : ready]->
              [tsk5 : ready]
          )-> [1 : ready]          //this is the auto-generated anonymous parent
      )-> [0 : ready]              //this is the auto-generated root
      */
    
    
     //we use a conder-factory to creat base-conder
     //    which return(true) if [tsk].param === 3
     //    else  return(false)
     //later we will USE evt.IF/evt.ELIF to wrap the base-conder                 
     // 首先写一个简单的生成 conder 模板 的函数
     //    [tsk].param === 3 时满足条件
     //    我们稍后要使用 evt.IF/evt.ELIF 把conder包起来
    
      function creat_conder(delay) {
          let _f = (rtrn_tru,rtrn_fls,self)=> {
              console.log(self.name_,'started conder at',new Date())
              setTimeout(
                  ()=> {
                      console.log(self.name_,'finish conder at',new Date())
                      if(self.param === 3) {
                          rtrn_tru()
                      } else {
                          rtrn_fls()
                      }
                  },
                  delay
              )
         }
         return(_f)
      }
    
      //the ctrl logic to impl:
      //我们实现如下逻辑
      /*
          if(param === 0) {
              [tsk0].exec()
          } else if(param ===1) {
              [tsk1].exec()
          } else if(param ===2) {
              [tsk2].exec()
          } else if(param ===3) {
              [tsk3].exec()
          } else if(param ===3) {
              //impossible branch
              [tsk4].exec()
          } else {
              //impossible branch
              [tsk5].exec()
          }
    
      */
    
      //使用evt.IF 和  evt.ELIF
      //  需要 evt.IF(conder)  evt.ELIF(conder)
      //使用evt.ELSE 不用带参数
      //   evt.ELSE is internally a special base-conder
      //   it is NOT a conder-wrapper
      //   so use it without conder-param
    
    
      tsk.T_.tsk0.param               = 0
      tsk.T_.tsk0.conder_             = evt.IF(creat_conder(10000))
      tsk.T_.tsk0.executor_           = creat_executor(2000)
    
      tsk.T_.tsk1.param               = 1
      tsk.T_.tsk1.conder_             = evt.ELIF(creat_conder(10000))
      tsk.T_.tsk1.executor_           = creat_executor(2000)
    
    
      tsk.T_.tsk2.param               = 2
      tsk.T_.tsk2.conder_             = evt.ELIF(creat_conder(10000))
      tsk.T_.tsk2.executor_           = creat_executor(2000)
    
    
      tsk.T_.tsk3.param               = 3
      tsk.T_.tsk3.conder_             = evt.ELIF(creat_conder(10000))
      tsk.T_.tsk3.executor_           = creat_executor(2000)
    
    
      tsk.T_.tsk4.param               = 3
      tsk.T_.tsk4.conder_             = evt.ELIF(creat_conder(10000))
      tsk.T_.tsk4.executor_           = creat_executor(2000)
    
    
      tsk.T_.tsk5.param               = 3
      tsk.T_.tsk5.conder_             = evt.ELSE 
                                      //ELSE have no conder-param
      tsk.T_.tsk5.executor_           = creat_executor(2000)
    
    
      /*
          > tsk.$sdfs_.map(nd=>nd.conder_)
          [
            [Function: DFLT_CU_CONDER],
            [Function: DFLT_CU_CONDER],
            [Function: _if] { [Symbol(if)]: true },
            [Function: _elif] { [Symbol(elif)]: true },
            [Function: _elif] { [Symbol(elif)]: true },
            [Function: _elif] { [Symbol(elif)]: true },
            [Function: _elif] { [Symbol(elif)]: true },
            [Function: ELSE] { [Symbol(else)]: true }
          ]
          > tsk.$sdfs_.map(nd=>nd)
          [
            Task [0 : ready] {},
            Task [1 : ready] {},
            Task [tsk0 : ready] { param: 0 },
            Task [tsk1 : ready] { param: 1 },
            Task [tsk2 : ready] { param: 2 },
            Task [tsk3 : ready] { param: 3 },
            Task [tsk4 : ready] { param: 3 },
            Task [tsk5 : ready] { param: 3 }
          ]
    
      */
    
      var p = tsk.launch()
      >
      tsk0 started conder at 2021-12-16T13:06:52.321Z
      >
      tsk.show()

mixed-blue-print-state10

    >
    tsk0 finish conder at 2021-12-16T13:07:02.332Z
    tsk1 started conder at 2021-12-16T13:07:02.339Z
    >
    tsk.show()

mixed-blue-print-state11

    > 
    tsk1 finish conder at 2021-12-16T13:07:12.354Z
    tsk2 started conder at 2021-12-16T13:07:12.355Z
    > 
    tsk.show()

mixed-blue-print-state12

    > 
    tsk2 finish conder at 2021-12-16T13:07:22.364Z
    tsk3 started conder at 2021-12-16T13:07:22.365Z
    tsk3 finish conder at 2021-12-16T13:07:32.374Z
    tsk3 started at 2021-12-16T13:07:32.374Z
    tsk3 succ at 2021-12-16T13:07:34.378Z
    0 started at 2021-12-16T13:07:34.384Z
    0 succ at 2021-12-16T13:07:36.392Z
    >

    tsk.show() 

mixed-blue-print-state13

    tsk.soft_reset()

while

    tsk.soft_reset()

    //we change the base-conder and creat_executor to TEST evt.WHILE  
    //我们改变一下creat_conder 和 creat_executor 的逻辑
    //实验一下 WHILE 关键字

    function creat_conder(delay) {
        let _f = (rtrn_tru,rtrn_fls,self)=> {
            console.log(self.name_,'started conder at',new Date())
            setTimeout(
                ()=> {
                    console.log(self.name_,'finish conder at',new Date(),self.param)
                    if(self.param < 3) {       //==================>
                        rtrn_tru()
                    } else {
                        rtrn_fls()
                    }
                },
                delay
            )
       }
       return(_f)
    }

    function creat_executor(delay) {
        let _f = (rtrn,thrw,self)=> {
            console.log(self.name_,'started at',new Date())
            setTimeout(
                ()=> {
                    console.log(self.name_,'succ at',new Date())
                    self.param = self.param +1       //==================>
                    rtrn(self.name_)
                },
                delay
            )
       }
       return(_f)
    }
  
    ////

    tsk.executor_                   = creat_executor(2000)


    tsk.T_.tsk0.param               = 0                 //========================>
    tsk.T_.tsk0.conder_             = evt.WHILE(creat_conder(1000))
    tsk.T_.tsk0.executor_           = creat_executor(2000)

    tsk.T_.tsk1.param               = 0                 //========================>
    tsk.T_.tsk1.conder_             = evt.WHILE(creat_conder(1000))
    tsk.T_.tsk1.executor_           = creat_executor(2000)


    tsk.T_.tsk2.param               = 0                 //========================>
    tsk.T_.tsk2.conder_             = evt.WHILE(creat_conder(1000))
    tsk.T_.tsk2.executor_           = creat_executor(2000)


    tsk.T_.tsk3.param               = 0                 //========================>
    tsk.T_.tsk3.conder_             = evt.WHILE(creat_conder(1000))
    tsk.T_.tsk3.executor_           = creat_executor(2000)


    tsk.T_.tsk4.param               = 0                  //========================>
    tsk.T_.tsk4.conder_             = evt.WHILE(creat_conder(1000))
    tsk.T_.tsk4.executor_           = creat_executor(2000)


    tsk.T_.tsk5.param               = 0                   //========================>
    tsk.T_.tsk5.conder_             = evt.WHILE(creat_conder(1000))       
    tsk.T_.tsk5.executor_           = creat_executor(2000)

    //// 
   
        /*
        > tsk.$sdfs_.map(nd=>nd.conder_)
        [
          [Function: DFLT_CU_CONDER],                         //DFLT_CU_CONDER will do NOTHING
          [Function: DFLT_CU_CONDER],                         //DFLT_CU_CONDER will do NOTHING
          [Function: _while_frame] { [Symbol(while)]: true },
          [Function: _while_frame] { [Symbol(while)]: true },
          [Function: _while_frame] { [Symbol(while)]: true },
          [Function: _while_frame] { [Symbol(while)]: true },
          [Function: _while_frame] { [Symbol(while)]: true },
          [Function: _while_frame] { [Symbol(while)]: true }
        ]
        >

        > tsk.$sdfs_.map(nd=>nd)
        [
          Task [0 : ready] {},
          Task [1 : ready] {},
          Task [tsk0 : ready] { param: 0 },
          Task [tsk1 : ready] { param: 0 },
          Task [tsk2 : ready] { param: 0 },
          Task [tsk3 : ready] { param: 0 },
          Task [tsk4 : ready] { param: 0 },
          Task [tsk5 : ready] { param: 0 }
        ]
        */

        var p = tsk.launch()

        /*
        > var p = tsk.launch()
        tsk0 started conder at 2021-12-17T05:55:10.668Z
        tsk0 finish conder at 2021-12-17T05:55:11.672Z 0
        tsk0 started at 2021-12-17T05:55:11.678Z   <-------------------------------------
        tsk0 succ at 2021-12-17T05:55:13.687Z      ------------------------------------->
        tsk0 started conder at 2021-12-17T05:55:13.689Z
        tsk0 finish conder at 2021-12-17T05:55:14.694Z 1
        tsk0 started at 2021-12-17T05:55:14.698Z   <-------------------------------------
        tsk0 succ at 2021-12-17T05:55:16.705Z      ------------------------------------->
        tsk0 started conder at 2021-12-17T05:55:16.706Z
        tsk0 finish conder at 2021-12-17T05:55:17.709Z 2
        tsk0 started at 2021-12-17T05:55:17.712Z    <-------------------------------------
        tsk0 succ at 2021-12-17T05:55:19.713Z       ------------------------------------->
        tsk0 started conder at 2021-12-17T05:55:19.714Z
        tsk0 finish conder at 2021-12-17T05:55:20.716Z 3
        tsk1 started conder at 2021-12-17T05:55:20.718Z
        tsk1 finish conder at 2021-12-17T05:55:21.720Z 0
        tsk1 started at 2021-12-17T05:55:21.724Z
        tsk1 succ at 2021-12-17T05:55:23.734Z
        tsk1 started conder at 2021-12-17T05:55:23.738Z
        tsk1 finish conder at 2021-12-17T05:55:24.744Z 1
        tsk1 started at 2021-12-17T05:55:24.748Z
        tsk1 succ at 2021-12-17T05:55:26.756Z
        tsk1 started conder at 2021-12-17T05:55:26.757Z
        tsk1 finish conder at 2021-12-17T05:55:27.759Z 2
        tsk1 started at 2021-12-17T05:55:27.759Z
        tsk1 succ at 2021-12-17T05:55:29.762Z
        tsk1 started conder at 2021-12-17T05:55:29.763Z
        tsk1 finish conder at 2021-12-17T05:55:30.766Z 3
        tsk2 started conder at 2021-12-17T05:55:30.767Z
        tsk2 finish conder at 2021-12-17T05:55:31.769Z 0
        tsk2 started at 2021-12-17T05:55:31.770Z
        tsk2 succ at 2021-12-17T05:55:33.774Z
        tsk2 started conder at 2021-12-17T05:55:33.778Z
        tsk2 finish conder at 2021-12-17T05:55:34.782Z 1
        tsk2 started at 2021-12-17T05:55:34.785Z
        tsk2 succ at 2021-12-17T05:55:36.790Z
        tsk2 started conder at 2021-12-17T05:55:36.791Z
        tsk2 finish conder at 2021-12-17T05:55:37.795Z 2
        tsk2 started at 2021-12-17T05:55:37.796Z
        tsk2 succ at 2021-12-17T05:55:39.798Z
        tsk2 started conder at 2021-12-17T05:55:39.801Z
        tsk2 finish conder at 2021-12-17T05:55:40.804Z 3
        tsk3 started conder at 2021-12-17T05:55:40.810Z
        tsk3 finish conder at 2021-12-17T05:55:41.812Z 0
        tsk3 started at 2021-12-17T05:55:41.813Z
        tsk3 succ at 2021-12-17T05:55:43.819Z
        tsk3 started conder at 2021-12-17T05:55:43.820Z
        tsk3 finish conder at 2021-12-17T05:55:44.822Z 1
        tsk3 started at 2021-12-17T05:55:44.822Z
        tsk3 succ at 2021-12-17T05:55:46.827Z
        tsk3 started conder at 2021-12-17T05:55:46.832Z
        tsk3 finish conder at 2021-12-17T05:55:47.839Z 2
        tsk3 started at 2021-12-17T05:55:47.840Z
        tsk3 succ at 2021-12-17T05:55:49.847Z
        tsk3 started conder at 2021-12-17T05:55:49.847Z
        tsk3 finish conder at 2021-12-17T05:55:50.850Z 3
        tsk4 started conder at 2021-12-17T05:55:50.851Z
        tsk4 finish conder at 2021-12-17T05:55:51.855Z 0
        tsk4 started at 2021-12-17T05:55:51.858Z
        tsk4 succ at 2021-12-17T05:55:53.865Z
        tsk4 started conder at 2021-12-17T05:55:53.866Z
        tsk4 finish conder at 2021-12-17T05:55:54.867Z 1
        tsk4 started at 2021-12-17T05:55:54.870Z
        tsk4 succ at 2021-12-17T05:55:56.874Z
        tsk4 started conder at 2021-12-17T05:55:56.879Z
        tsk4 finish conder at 2021-12-17T05:55:57.886Z 2
        tsk4 started at 2021-12-17T05:55:57.888Z
        tsk4 succ at 2021-12-17T05:55:59.894Z
        tsk4 started conder at 2021-12-17T05:55:59.897Z
        tsk4 finish conder at 2021-12-17T05:56:00.902Z 3
        tsk5 started conder at 2021-12-17T05:56:00.903Z
        tsk5 finish conder at 2021-12-17T05:56:01.904Z 0
        tsk5 started at 2021-12-17T05:56:01.905Z
        tsk5 succ at 2021-12-17T05:56:03.910Z
        tsk5 started conder at 2021-12-17T05:56:03.912Z
        tsk5 finish conder at 2021-12-17T05:56:04.914Z 1
        tsk5 started at 2021-12-17T05:56:04.915Z
        tsk5 succ at 2021-12-17T05:56:06.916Z
        tsk5 started conder at 2021-12-17T05:56:06.918Z
        tsk5 finish conder at 2021-12-17T05:56:07.919Z 2
        tsk5 started at 2021-12-17T05:56:07.919Z
        tsk5 succ at 2021-12-17T05:56:09.923Z
        tsk5 started conder at 2021-12-17T05:56:09.926Z
        tsk5 finish conder at 2021-12-17T05:56:10.931Z 3
        0 started at 2021-12-17T05:56:10.936Z
        0 succ at 2021-12-17T05:56:12.944Z
        */
   
        tsk.soft_reset() 

wrap function for event-loop

  • see APIS.wrap for function-signature-detail

      //nv-task-event-tree provide 7 APIS for run a loop of tsk
      //evt 提供了7个API, 用来启动一个tsk loop
      //主要为方便一些使用,比如你想 24小时不间断的爬一个网站
      //    同时自动重试
    
          0. try_until_succ                  //直到task-tree 成功,遇到错误自动恢复继续
          1. limited_auto_recover_loop       //有限次数的try_until_succ,
          2. endless_auto_recover_loop       //无限次数的try_until_succ, 除非手动停止
          3. repeat_until_fail               // 有限次数的,直到遇到错误
          4. repeat_ignore_fail              // 有限次数的,忽略错误反复run,不自动恢复,而是每次重新run
          5. endless_repeat_loop_until_fail  //repeat_until_fail 的无限版, 除非手动停止 
          6. endless_repeat_loop_ignore_fail //repeat_ignore_fail 的无限版, 除非手动停止
    
     //this time we dont USE blue_print, we try load_from_json to build task-tree
     // J is a top-to-down style config
    
     //这次我们不使用blue_print, 我们使用load_from_json 构造task-tree
     //和blue_print不同, J 是自顶向下书写的传统模型
     //J 的好处是 可以 预先把 conder, executor 添在里面(但是这种方式不好,一团糟)
    
      var J = [
          'tsk00',{type:'serial'},[
              'tsk000',[
              ],
              'tsk001',{type:'parallel'},[
                  'tsk0010',
                  'tsk0011',
                  'tsk0012',
              ],
              'tsk002',{type:'parallel'},[
                  'tsk0020',
                  'tsk0021',
                  'tsk0022'
              ]
          ]
      ]
    
      var tsk = evt.load_from_json(J)
    
    
    
      /*
      tsk.show()
    
      (
          {
              [tsk000 : ready]         -|
              {
                  [tsk0010 : ready]-|
                  [tsk0011 : ready]-|
                  [tsk0012 : ready]-|
              }-> [tsk001 : ready]     -|
              {
                  [tsk0020 : ready]-|
                  [tsk0021 : ready]-|
                  [tsk0022 : ready]-|
              }-> [tsk002 : ready]     -|
          }-> [tsk00 : ready]
      )-> [@root@ : ready]
    
      */
    
      //we creat a random promise factory
      //我们创建一个随机resolve/reject 的 executor工厂
    
      function creat_executor(delay) {
          let _f = (rtrn,thrw,self)=> {
              console.log(self.name_,'started at',new Date())
              setTimeout(
                  ()=> {
                      let fail = Math.random() > 0.5;         //------------------------->
                      if(fail) {
                          console.log(self.name_,'failed at',new Date());
                          thrw(self.name_)
                      } else {
                          console.log(self.name_,'succ at',new Date());
                          rtrn(self.name_)
                      }
                  },
                  delay
              )
         }
         return(_f)
      }
    
    
          tsk.T_.tsk0020.executor_           = creat_executor(2000)
          tsk.T_.tsk0021.executor_           = creat_executor(2000)
          tsk.T_.tsk0022.executor_           = creat_executor(2000)
              tsk.T_.tsk002.executor_        = creat_executor(3000)
    
    
          tsk.T_.tsk001.$sdfs_.forEach(tsk=> {
              tsk.executor_  = creat_executor(2000)
          });
              tsk.T_.tsk001.executor_         = creat_executor(3000)
    
    
              tsk.T_.tsk000.executor_         = creat_executor(3000)
    
                    tsk.T_.tsk00.executor_    = creat_executor(4000)
                         tsk.executor_        =(rtrn,thrw,self) => {
                              rtrn(self.$sdfs_.map(nd=>nd.rslt_))
                         }
    
          ////
    
          var p = evt.wrap.try_until_succ(tsk)
    
      /*
      tsk000 started at 2021-12-17T06:27:20.933Z
      tsk000 failed at 2021-12-17T06:27:23.934Z              //------------>
      tsk000 started at 2021-12-17T06:27:23.946Z             //AUTO recover at FAILED node [tsk000]
      tsk000 succ at 2021-12-17T06:27:26.952Z
      tsk0010 started at 2021-12-17T06:27:26.959Z
      tsk0011 started at 2021-12-17T06:27:26.962Z
      tsk0012 started at 2021-12-17T06:27:26.966Z
      tsk0010 succ at 2021-12-17T06:27:28.963Z
      tsk0011 succ at 2021-12-17T06:27:28.966Z
      tsk0012 failed at 2021-12-17T06:27:28.969Z            //------------>
      tsk0012 started at 2021-12-17T06:27:28.971Z           //AUTO recover at FAILED node [tsk0012]
      tsk0012 succ at 2021-12-17T06:27:30.976Z
      tsk001 started at 2021-12-17T06:27:30.977Z
      tsk001 succ at 2021-12-17T06:27:33.984Z
      tsk0020 started at 2021-12-17T06:27:33.989Z
      tsk0021 started at 2021-12-17T06:27:33.993Z
      tsk0022 started at 2021-12-17T06:27:33.995Z
      tsk0020 succ at 2021-12-17T06:27:35.996Z
      tsk0021 succ at 2021-12-17T06:27:35.997Z
      tsk0022 failed at 2021-12-17T06:27:36.003Z             //------------>
      tsk0022 started at 2021-12-17T06:27:36.006Z            //AUTO recover at FAILED node [tsk0022]
      tsk0022 succ at 2021-12-17T06:27:38.010Z
      tsk002 started at 2021-12-17T06:27:38.011Z
      tsk002 succ at 2021-12-17T06:27:41.015Z
      tsk00 started at 2021-12-17T06:27:41.016Z
      tsk00 failed at 2021-12-17T06:27:45.023Z              //------------>
      tsk00 started at 2021-12-17T06:27:45.025Z            //AUTO recover at FAILED node [tsk00]
      tsk00 succ at 2021-12-17T06:27:49.030Z
    
      */
    
    
      /*
      > p
      Promise {
        [
          Symbol(noexist), 'tsk00',
          'tsk000',        'tsk001',
          'tsk0010',       'tsk0011',
          'tsk0012',       'tsk002',
          'tsk0020',       'tsk0021',
          'tsk0022'
        ],
        [Symbol(async_id_symbol)]: 99,
        [Symbol(trigger_async_id_symbol)]: 5,
        [Symbol(destroyed)]: { destroyed: false }
      }
      >
    
      */

load_from_json

PERFORMANCE TEST

  //now we try a big-task-tree of 500000 task-nodes to test the performance
  //   coz nv-task-event-tree is pure JS,so its performance NOT good enough

  //接下来我们准备一个巨大的 任务树 来测试下巨量异步任务的performance
  //   因为nv-task-event-tree 是纯JS实现的,所以它的performance一般般
  //   主要是内存耗费比较大(为了提速,使用了一些耗费内存的技巧)

  const {rand} = require("nv-random-tree")

  //准备一个随机产生异步任务的工厂

    function creat_executor(delay) {
        let _f = (rtrn,thrw,self)=> {
            setTimeout(
                ()=> {
                     rtrn(self.name_)
                },
                delay
            )
       }
       return(_f)
    }

   //creat 500000 task,each task have max-of-50 child-task 
   //创建任务树,大小为500000, 每个任务最多50个子任务节点

   var big_task_tree = rand(50,500000,undefined,evt.Task,2)

    /*
    > big_task_tree.$sdfs_.length
    500000
    >
    */


    big_task_tree.enable_promise()


    big_task_tree.$sdfs_.forEach(
        (nd,i)=> {
            nd.name_ = `tsk${i}`;
            let rand_type = (Math.random() >0.5)
            if(rand_type) {                       //随机生成 串行 或 并行 节点
                nd.set_as_serial()
            } else {
                nd.set_as_parallel()
            }
            nd.executor_ = creat_executor(Math.random()*2)  //每个任务延时 1-2 毫秒
        }
    );

     
    //you can see ,we have 62789 serial-task, 62454 is_parallel task, 374757 leaf-task 
    //总计 62789 个串行任务, 62454个并行任务,374757个叶子任务

    /*

    > big_task_tree.$sdfs_.filter(nd=>nd.$is_leaf()).length
    374757
    > big_task_tree.$sdfs_.filter(nd=>nd.is_serial() && !nd.$is_leaf()).length
    62789
    > big_task_tree.$sdfs_.filter(nd=>nd.is_parallel() && !nd.$is_leaf()).length
    62454
    >
    */

    /*
     87698 root      20   0 1005916 413616  33404 S  0.0 20.5   0:11.73 node
     
    > process.memoryUsage()
    {
      rss: 423542784,
      heapTotal: 381763584,
      heapUsed: 358841448,                        // about 350M memory for 500000 nodes
      external: 1066990,
      arrayBuffers: 24792
    }
    >
    */


    async function tst() {
        let start = new Date();
        let start_ms = start.getTime()
        console.log('begin at :',start);
        ////
        await big_task_tree.launch();
        ////
        let end = new Date();
        let end_ms = end.getTime()
        console.log('end at: ',end);
        console.log("costed: ", end_ms-start_ms,'ms')
    }


    > big_task_tree.p_
    Promise {
      <pending>,
      [Symbol(async_id_symbol)]: 51,
      [Symbol(trigger_async_id_symbol)]: 5,
      [Symbol(destroyed)]: { destroyed: false }
    }
    >

    tst()



    /*
    > tst()
    begin at : 2021-12-17T10:36:42.526Z
    Promise {
      <pending>,
      [Symbol(async_id_symbol)]: 171,
      [Symbol(trigger_async_id_symbol)]: 5,
      [Symbol(destroyed)]: { destroyed: false }
    }
    */

    //you can observe the current state with .running_  AND .rejected_at_
    //可以使用 .running_  和 .rejected_at_ 在任务树运行过程中观察


    /*
    > big_task_tree.running_
    Set(2) {
      Task [tsk328374 : self_executing] {},
      Task [tsk328488 : self_executing] {}
    }
    > big_task_tree.running_
    Set(16) {
      Task [tsk330086 : self_executing] {},
      Task [tsk330100 : self_executing] {},
      Task [tsk330102 : self_executing] {},
      Task [tsk330105 : self_executing] {},
      Task [tsk330111 : self_executing] {},
      Task [tsk330120 : self_executing] {},
      Task [tsk330122 : self_executing] {},
      Task [tsk330126 : self_executing] {},
      Task [tsk330134 : self_executing] {},
      Task [tsk330138 : self_executing] {},
      Task [tsk330144 : self_executing] {},
      Task [tsk330149 : self_executing] {},
      Task [tsk330157 : self_executing] {},
      Task [tsk330160 : self_executing] {},
      Task [tsk330161 : self_executing] {},
      Task [tsk330166 : self_executing] {}
    }
    .......
    */



    /*
    > end at:  2021-12-17T10:37:07.224Z
    costed:  24698 ms

    > big_task_tree.p_
    Promise {
      'tsk0',
      [Symbol(async_id_symbol)]: 51,
      [Symbol(trigger_async_id_symbol)]: 5,
      [Symbol(destroyed)]: { destroyed: false }
    }
    >
    > big_task_tree.$sdfs_
    [
      Task [tsk0 : resolved] {},
      Task [tsk1 : resolved] {},
      .....
      Task [tsk98 : resolved] {},
      Task [tsk99 : resolved] {},
      ... 499900 more items
    ]
    >
    */


    !!!!IMPORTANT!!!!
    //you can get the blue_print back for topology AND reusing
    //可以使用.unparse() 来获取blue_print
    var blue_print = big_task_tree.unparse()
    

    /* 
            > bp
            '{\n' +
              '    {\n' +
              '        (\n' +
              '            (\n' +
              '                (\n' +
              '                    (\n' +
              '                        (\n' +
              '                            [tsk7]\n' +
              '                        )-> [tsk6]-> \n' +
              '                        (\n' +
              '                            {\n' +
              '                                (\n' +
              '                                    {\n' +
              '                                        (\n' +
              '                                            [tsk13]-> \n' +
              '                                            [tsk14]-> \n' +
              '                                            [tsk15]-> \n' +
              '                                            [tsk16]-> \n' +
              '                                            [tsk17]-> \n' +
              '                                            [tsk18]-> \n' +
              '                                            [tsk19]\n' +
              '                                        )-> [tsk12]        -| \n' +
              '                                        {\n' +
              '                                            [tsk21]    -| \n' +
              '                                            [tsk22]    -| \n' +
              '                                            [tsk23]    -| \n' +
              '                                        }-> [tsk20]        -| \n' +
              ...........

      */

  

dump

 // .unparse() can ONLY get the topology(blue_print) BACK
 // .unparse() 只能拿回topology(blue_print)


 //if you need full info(conder,executor,props..., task-node-type,) BACK
 // USE .dump()
 // 如果需要详细的全部现场,使用 .dump()

 //dumped JSON could be reload by evt.load_from_json(J)

        > var J = big_task_tree.dump()

        /*
              .....
              [Object],    [Array],     'tsk495452', [Object],    [Array],
              'tsk495495', [Object],    [Array],     'tsk495525', [Object],
              [Array],     'tsk495533', [Object],    'tsk495534', [Object],
              [Array],     'tsk495556', [Object],    [Array],     'tsk495572',
              [Object],    [Array],     'tsk495605', [Object],    'tsk495606',
              [Object],    [Array],     'tsk495615', [Object],    [Array],
              'tsk495650', [Object],    'tsk495651', [Object],    'tsk495652',
              [Object],    [Array],     'tsk495672', [Object],    [Array],
              'tsk495688', [Object],    [Array],     'tsk495717', [Object],
              [Array],     'tsk495737', [Object],    [Array],     'tsk495769',
              [Object],    [Array],     'tsk495817', [Object],    [Array],
              'tsk495823', [Object],    [Array],     'tsk495839', [Object],
              'tsk495840', [Object],    [Array],     'tsk495876', [Object],
              [Array],     'tsk495916', [Object],    [Array],     'tsk495949',
              [Object],    [Array],     'tsk495983', [Object],    'tsk495984',
              ... 33 more items
            ],
            'tsk496189',
            {
              type: '1',
              enable_promise: false,
              conder: [Function: DFLT_CU_CONDER],
              executor: [Function: _f],
              args_dict: {}
            },
            ... 30 more items
          ]
        ]
        >
        */


        big_task_tree.soft_reset()

IN BROWSER

    <html>
       <head>
           <script src="https://github.com/navegador5/nv-task-event-tree/blob/master/RESOURCES/evt.min.js"> </script>
       </head>
    </html>

    const evt = nvhtml.evt;          //==================>


    //BROWSER VERSION add two more FEATURE for future using(
    //         one for CSS ,the other for kvtree
    //), so its pkg is  BIG

    SELECT-CFG:
            var J = [
                 'color', {type:'Multi',as:'ary'},[
                      'blue',
                      'yellow',
                      'green',
                      'radio',{type:"Radio"},[
                           "white",
                           "black"
                      ],
                      'other',{type:"Setter",validate:function(clr) {return(["red","grey","purple"].includes(clr))}}
                 ]
            ]
  
          var [rt,forest] = nvhtml.select.load_from_json(J)
          rt.val_
          rt.color.blue.slct_self() 
          rt.val_         
  
    JNODE:
        var [rt,forest] = nvhtml.parse_from_json({a:100,b:[5,true,3,false]},forest)

APIS

load

load_from_blue_print(bp:BP,max_size=10000,rtrn_forest=false,tag_parser=DFLT_TAG_PARSER)

load_from_blue_print(bp:BP,max_size=10000,rtrn_forest=false,tag_parser=DFLT_TAG_PARSER)

    max_size means must larger than (2* task-node-count)
        1000000 task-nodes will cost about 90M memory
        normally  10000  task-nodes is enough for most secarino
   BP is a string:
       {...}        means parallel task, it will start children at the same time,similiar to Promise.all
       (...)        means serial task,   it will start in DFS-sequence, similar to html-traverse sequence
       [task-name]  task-name MUST be enclosed in []
       ->           means parent task is serial,   is OPTIONAL   (coz '(...)' already decided)
       -|           means parent task is parallel, is OPTIONAL  (coz '{...}' already decided)
   BP is written in BOTTOM-TO-UP style:


     var blue_print = `
         {
             [tsk000]         -|
             (
                 [tsk0010]->
                 [tsk0011]->
                 [tsk0012]
             )-> [tsk001]     -|
             {
                 [tsk0020]-|
                 [tsk0021]-|
                 [tsk0022]-|
             }-> [tsk002]     -|
         }-> [tsk00]
     `
     the task execute sequence for each layer will be:


             <Serial>([tsk0010]->[tsk0011]->[tsk0012])->[tsk001];

             <Parallel>{
                 [tsk0020]-|
                 [tsk0021]-| ->[tsk002];
                 [tsk0022]-|
             }

         <Parallel>{
            [tsk000] -|
            [tsk001] -| -> [tsk00]
            [tsk002] -|
         }

     the details are:

         <Parallel>[tsk00] ^start
             <Leaf>    [tsk000] ^start executing... -> &[tsk000] ended$        -|
             </Leaf>   [tsk000]
                 -> %notify-to(&[tsk00])

             <Serial>  [tsk001] ^start-first-child                             -|
                  [tsk0010] ^start executing... -> [tsk0010] ended$ ->
                  [tsk0011] ^start executing... -> [tsk0011] ended$ ->
                  [tsk0012] ^start executing... -> [tsk0012] ended$ ->
                      %notify-to(&[tsk001])
             </serial> [tsk001]
                  %recv-from-last-child(&[tsk0012]) ->
                  [tsk001] ^start executing... ended$
                  -> %notify-to(&[tsk00])

             <Parallel>[tsk002] ^start-children-at-same-time                    -|
                   <Leaf>    [tsk0020] ^start-at-same-time-with-siblings  -|
                       [tsk0020] ^start executing... -> [tsk0020] ended$
                   </Leaf>   [tsk0020]
                        -> %notify-to(&[tsk002])

                   <Leaf>    [tsk0021] ^start-at-same-time-with-siblings  -|
                       [tsk0021] ^start executing... -> [tsk0021] ended$
                   </Leaf>   [tsk0021]
                        -> %notify-to(&[tsk002])

                   <Leaf>    [tsk0022] ^start-at-same-time-with-siblings  -|
                       [tsk0022] ^start executing... -> [tsk0022] ended$
                   </Leaf>   [tsk0022]
                        -> %notify-to(&[tsk002])

            </Parallel>[tsk002]
                 %recv-from-children(&[tsk0020],&[tsk0021],&[tsk0022]) ->
                 [tsk002] ^start executing... ended$
                 -> %notify-to(&[tsk00])

       </Parallel>[tsk00]
            %recv-from-children(&[tsk000],&[tsk001],&[tsk002]) ->
            [tsk00] ^start executing... ended$
            -> %notify-to(@root@)

       @root@ will settle promise on It

load_from_json

    load_from_json(J)
    J: [T?,A?,C?]
         T@optional : String, if-skipped, it will be a DFS-index
         A@optional : CFG
         C@optional : Array<J>

    CFG: {
        type: 'serial',                          //'serial' OR 'parallel'
                                                 //    default is 'serial'
        enable_promise: false,                   // enable_promise on task-node , make the task awaitable
                                                 //    default only on root-task-node is true
                                                 //                 on nonroot-task-node is false
        executor: [Function: DFLT_CU_EXECUTOR],  // (rtrn,thrw,self)=>{...}
                                                 //     rtrn: similiar to return/resolve
                                                 //     thrw: similiar to throw/reject
        conder: [Function: DFLT_CU_CONDER],      // (rtrn_tru,rtrn_fls,self) => {}
                                                 //     supported ctrl-flow keyword
                                                 //        IF(conder)
                                                 //        ELIF(conder)   ELSE; //ELSE-have-no-params
                                                 //        WHILE(conder)
        args_dict: {}                            // for init props
                                                 //     task-event-tree NOT support variable
                                                 //            use props on task-node instead

    }

    valid-ptrn:
        [T],[A],[C],
        [T,A],[T,C],[A,C],
        [T,A,C]

ctrl keywords

 //param conder:(rtrn_tru,rtrn_fls,self) => {...}
 IF(conder),
 ELIF(conder),
 ELSE,            //no parameter
 WHILE(conder)

wrap

 async function try_until_succ(tsk,max_times=Infinity):any
 async function limited_auto_recover_loop(tsk,times=1,history_size=10):{history:Array,counter:{c:Number}}
       function endless_auto_recover_loop(tsk,history_size=10):{history:Array,counter:{c:Number}}
 async function repeat_until_fail(tsk,times=1,history_size=10):{history:Array,counter:{c:Number}}
 async function repeat_ignore_fail(tsk,times=1,history_size=10):{history:Array,counter:{c:Number}}
       function endless_repeat_loop_until_fail(tsk,history_size=10):{history:Array,counter:{c:Number}}
       function endless_repeat_loop_ignore_fail(tsk,history_size=10):{history:Array,counter:{c:Number}}

brief

    > evt
    {
      debug: [Function: debug],
      noexist: Symbol(noexist),
      TYPES: { '0': 'serial', '1': 'parallel', serial: '0', parallel: '1' },
      DFLT_TAG_PARSER: [Function: DFLT_TAG_PARSER],
      load_from_blue_print: [Function: load_from_blue_print],
      DFLT_CFG: [Function: DFLT_CFG],
      load_from_json: [Function: load_from_json],
      IF: [Function: IF],
      ELIF: [Function: ELIF],
      ELSE: [Function: ELSE] { [Symbol(else)]: true },
      WHILE: [Function: WHILE],
      wrap: {
        try_until_succ: [AsyncFunction: try_until_succ],
        limited_auto_recover_loop: [AsyncFunction: limited_auto_recover_loop],
        endless_auto_recover_loop: [Function: endless_auto_recover_loop],
        repeat_until_fail: [AsyncFunction: repeat_until_fail],
        repeat_ignore_fail: [AsyncFunction: repeat_ignore_fail],
        endless_repeat_loop_until_fail: [Function: endless_repeat_loop_until_fail],
        endless_repeat_loop_ignore_fail: [Function: endless_repeat_loop_ignore_fail]
      }
    }
    > evt.DFLT_CFG()
    {
      type: 'serial',
      enable_promise: false,
      conder: [Function: DFLT_CU_CONDER],
      executor: [Function: DFLT_CU_EXECUTOR],
      args_dict: {}
    }
    >
    > evt.DFLT_TAG_PARSER.toString()
    '(s)=>s.trim()'
    >

METHODS

task

    tsk.conding_deses_                          tsk.fst_bubble_paused_ance_
    tsk.fst_bubble_rejected_ance_               tsk.fst_paused_ance_
    tsk.fst_rejected_ance_                      tsk.fst_self_paused_ance_
    tsk.fst_self_rejected_ance_                 tsk.has_bubble_paused_ance_
    tsk.has_bubble_rejected_ance_               tsk.has_paused_ance_
    tsk.has_rejected_ance_                      tsk.has_self_paused_ance_
    tsk.has_self_rejected_ance_                 tsk.is_bubble_paused
    tsk.is_bubble_rejected                      tsk.is_conding
    tsk.is_impossible                           tsk.is_opened
    tsk.is_paused                               tsk.is_pending
    tsk.is_ready                                tsk.is_rejected
    tsk.is_resolved                             tsk.is_self_executing
    tsk.is_self_paused                          tsk.is_self_rejected
    tsk.is_settled                              tsk.is_started
    tsk.is_stopped                              tsk.is_stucked
    tsk.self_executing_deses_                   tsk.self_rejected_deses_
    tsk.state_

    tsk.cond_                                   tsk.disable_promise
    tsk.enable_promise                          tsk.exception_
    tsk.is_promise_enabled                      tsk.p_
    tsk.rslt_                                   tsk.settled_

    tsk.conder_                                 tsk.executor_
    tsk.if_head_                                tsk.is_abandoned
    tsk.is_all_if_chain_psib_conder_failed      tsk.is_conder_elif
    tsk.is_conder_else                          tsk.is_conder_if
    tsk.is_conder_while                         tsk.undefined

    tsk.T_                                      tsk.carryon
    tsk.constructor                             tsk.continue
    tsk.dump                                    tsk.hard_reset
    tsk.is_parallel                             tsk.is_serial
    tsk.launch                                  tsk.name_
    tsk.pause                                   tsk.recover
    tsk.rejected_at_                            tsk.running_
    tsk.set_as_parallel                         tsk.set_as_serial
    tsk.show                                    tsk.soft_reset
    tsk.unparse

internal tree

    tsk.$add_lsib                               tsk.$add_lsibs
    tsk.$add_or_goto_parent                     tsk.$add_parent
    tsk.$add_parent_and_lsib                    tsk.$add_rsib
    tsk.$add_rsibs                              tsk.$ance
    tsk.$ance_dist                              tsk.$ances_
    tsk.$append_child                           tsk.$append_children
    tsk.$are_sibs                               tsk.$bfs_
    tsk.$bfs_des_index                          tsk.$bfs_des_leaf_index
    tsk.$bfs_des_next                           tsk.$bfs_des_nonleaf_index
    tsk.$bfs_des_prev                           tsk.$bfs_index_
    tsk.$bfs_leaf_index_                        tsk.$bfs_next_
    tsk.$bfs_nonleaf_index_                     tsk.$bfs_prev_
    tsk.$block                                  tsk.$blocked_
    tsk.$bpl_                                   tsk.$breadth_
    tsk.$child                                  tsk.$children_
    tsk.$children_count_                        tsk.$clone
    tsk.$cmmn_ances                             tsk.$cond_leaf_sdfs_next
    tsk.$cond_leaf_sedfs_next                   tsk.$connto
    tsk.$deep_lseq                              tsk.$deep_steq
    tsk.$depth_                                 tsk.$des_bfs_
    tsk.$des_bpl                                tsk.$des_breadth
    tsk.$des_lyr                                tsk.$des_lyr_next
    tsk.$des_lyr_prev                           tsk.$des_lyrs_
    tsk.$des_offset                             tsk.$des_own_lyr
    tsk.$des_pbreadth                           tsk.$des_plyr
    tsk.$des_spl                                tsk.$disconn
    tsk.$dist                                   tsk.$dlmost_
    tsk.$drmost_                                tsk.$dump
    tsk.$edfs_                                  tsk.$edfs_des_index
    tsk.$edfs_des_leaf_index                    tsk.$edfs_des_nonleaf_index
    tsk.$edfs_index_                            tsk.$edfs_leaf_index_
    tsk.$edfs_next_                             tsk.$edfs_nonleaf_index_
    tsk.$edfs_prev_                             tsk.$erase
    tsk.$erase_r                                tsk.$fid_
    tsk.$forest_                                tsk.$fsib
    tsk.$fsibs_                                 tsk.$fsibs_count_
    tsk.$fst_cmmn_ance                          tsk.$fstch_
    tsk.$fstpsib_                               tsk.$fstsib_
    tsk.$gen_ance                               tsk.$gen_bfs
    tsk.$gen_child_from_fst                     tsk.$gen_child_from_lst
    tsk.$gen_cond_leaf_sdfs_next                tsk.$gen_cond_leaf_sedfs_next
    tsk.$gen_des_bfs                            tsk.$gen_des_lyr
    tsk.$gen_des_lyr_next                       tsk.$gen_des_lyr_prev
    tsk.$gen_edfs_next                          tsk.$gen_edfs_next_leaf
    tsk.$gen_edfs_next_nonleaf                  tsk.$gen_edfs_prev
    tsk.$gen_edfs_prev_leaf                     tsk.$gen_edfs_prev_nonleaf
    tsk.$gen_fsib                               tsk.$gen_lmost
    tsk.$gen_lyr                                tsk.$gen_lyr_next
    tsk.$gen_lyr_prev                           tsk.$gen_psib
    tsk.$gen_rmost                              tsk.$gen_sdfs_next
    tsk.$gen_sdfs_next_build_action             tsk.$gen_sdfs_next_ignore_blocked
    tsk.$gen_sdfs_next_leaf                     tsk.$gen_sdfs_next_nonleaf
    tsk.$gen_sdfs_next_srch_action              tsk.$gen_sdfs_prev
    tsk.$gen_sdfs_prev_build_action             tsk.$gen_sdfs_prev_leaf
    tsk.$gen_sdfs_prev_nonleaf                  tsk.$gen_sdfs_prev_srch_action
    tsk.$gen_sedfs_next                         tsk.$gen_sedfs_next_afte