Newly Practicing Mortician

    event-sequence-listener
    TypeScript icon, indicating that this package has built-in type declarations

    0.6.4 • Public • Published

    build status npm version dependencies bundle size

    Purpose

    When it comes to reacting with a series of events, you may want to try this:

     
    video.on('loadedmetadata',function () {
      video.on('play', function() {
        video.on('pause', function() {
          // respond to loadedmetadata->play->pause
          // ...
        })
      })
    })

    The solution may issue undesired behavior because the play & pause event listeners are attached latter rather than the first stage, it may accidentally change the callback calling order which arranges carefully; increases the difficulty to debug & trace.

    Or you may want to flat the codes by using a lot of flags:

     
    let isLoadedmetadata = false
    let isPlay = false
     
    video.on('loadedmetadata',function () {
     isLoadedmetadata = true
    })
     
    video.on('play', function() {
      if(isLoadedmetadata) {
        isPlay = true
      }
    })
     
    video.on('pause', function() {
      if(isPlay) {
          // respond to loadedmetadata->play->pause
          // ...
        }
    })
     

    As you can see, it doesn't better than the first solution; it is annoyed to manage the tons of flags; also increase the complexity and not easy to understand the codes.

    Benefit

    By using the tool, you can listen to the sequence of events in a beautiful way:

     
    import EventSequenceListener from 'event-sequence-listener'
     
    const eventSequence = new EventequenceListener(
      ['loadedmetadata', 'play', 'pause'],
      {
        listener: video,
        scheduleType: 'repeat'
      }
    })
     
    function run() {
      eventSequence.promise.then(resolvedData => {
        // respond to loadedmetadata->play->pause
        // ...
        // Wait next sequence arrived
        run()
      })
    }
     
    run()

    Watch more than one event sequences and get the result as soon as one of them get fulfilled or rejected.

     
    async eventSequenceRace() {
      const eventSequence = new EventequenceListener(
        [
          ['loadedmetadata', 'pause', 'play'],
          ['loadedmetadata', 'play'],
        ]
        {
          listener: video,
          unionScheduleType: 'race'
        }
      })
     
      const resolvedData = await eventSequence.promise
      // The value depends on which event sequences finished first
      console.log(resolvedData[0].passEvents)
    }
     

    If the event sequence is the right-most subset of other event sequences, make sure the longer event sequence put in front of the short one when there is a raced condition:

     
    async eventSequenceRace() {
      const eventSequence = new EventSequenceListener(
        [
          ['enter-vod', 'loadedmetadata', 'play'],
          ['loadedmetadata', 'play']
        ]
        {
          listener: video,
          unionScheduleType: 'race',
          scheduleType: 'repeat'
        }
      })
     
      while(true) {
        const [ result ] = await eventSequence.promise
        console.log(result)
      }
    }
     

    Feature

    define a callback for each event

    The listened event can be a string or object, and the object can be assigned a function to cb property, which calls whenever the event gets triggered.

    The callback cb defined in the second parameter gets executed when the event sequence is complete.

      const eventSequence = new EventSequenceListener(
        [
          'event1',
          {
            name: 'event2',
            // optional property
            cb(metadata) {}
          }
        ]
        {
          // required property
          listener: eventTarget,
          // ended callback, optional property
          cb(metadata) {}
        }
      })

    setup custom data

    You can customize the data that passed to each event callback, and the data can be updated by returning it from the callback. The successor will receive last updated data.

    If cb doesn't return truthy value, the predecessor's data will pass to the next event callback.

    Also ended callback can return modified data; the promise retrieved by promise getter will resolve the data passed from the first event cb callback down to the ended callback.

      const eventSequence = new EventSequenceListener(
        [
          'event1',
          {
            name: 'event2',
            cb(metadata) {
              const data = metadata[0].data
              data.count++
              return data
            }
          }
        ]
        {
          listener: eventTarget,
          cb(metadata) {
              const data = metadata[0].data
              data.count++
              return data
          },
          // optional property
          initData: {
            count: 0
          }
        }
      })
     
      eventSequence.promise.then(metadata => {
        console.log(metadata[0].data.count) // print 2
      })

    get the arguments passed to each event listener

    All the arguments passed to each event listener will be available by accessing eventListenerArgs property. If the event is specified the threshold number, all the arguments of events before the final one will ignore.

      const eventSequenceListener = new EventSequenceListener(
        [
          'event1',
          {
            name: 'event2',
            cb(metadata) {
              console.log(metadata[0].eventListenerArgs)
            }
          },
          'event3'
        ],
        {
          listener,
          scheduleType: 'repeat',
          cb(metadata) {
            console.log(metadata[0].eventListenerArgs)
          }
        }
      )
     
      const result = await eventSequenceListener.promise
      console.log(result[0].eventListenerArgs)

    Monitor more than one event sequences

    For example, we have to do something after a pause event happened but only if at least one play event happened before the pause event, we can try this:

      const eventSequence = new EventSequenceListener(
        [
          ['play','pause'],
          ['pause']
        ]
        {
          listener: video,
          unionScheduleType: 'race',
          scheduleType: 'repeat'
        }
      })
     
      while (true) {
        const [result] = await eventSequence.promise
        if (result.passEvents[0] === 'play') {
          break
        }
      }
     
      // Now we can do what we want because the play event has happened
      do {
        //...
      } while (true)

    Or you can wait for all the event sequence:

      const eventSequence = new EventSequenceListener(
        [
          ['play','pause'],
          ['seeking', 'seeked']
        ]
        {
          listener: video,
          unionScheduleType: 'all',
          scheduleType: 'repeat'
        }
      })
     
      while (true) {
        const [firstEventSeqResult, secondEventSeqResult] = await eventSequence.promise
        //...
      }

    Check out the unit test files to learn how to use this module: examples

    Type Docs

    For more detail information, read the following link: https://dustin71728.github.io/event-sequence-listener/

    Fixed Bugs

    2019-03-05

    Fix the issue that may throw unhandled rejection when specifying the configurations:

    {
      unionScheduleType: 'race',
      scheduleType: 'repeat'
    }

    2020-02-29

    Upgrade all the dependencies. Fix type errors due to upgrading to typescript v3.8 Apply more accurate type to eventListenerArgs

    Install

    npm i event-sequence-listener

    DownloadsWeekly Downloads

    0

    Version

    0.6.4

    License

    MIT

    Unpacked Size

    78 kB

    Total Files

    11

    Last publish

    Collaborators

    • kiwi.liu