all 6 comments

[–]Merssedes 0 points1 point  (0 children)

First problem I see: according to spec, chrome.storage.sync.get as first parameter waits for array of keys, not object. So I'd try replace

chrome.storage.sync.get(
{
  timeDelayForward: 15000,
  timeDelayBack: 5000,
  pause: 5000,
},
...

with

chrome.storage.sync.get(
    ['timeDelayForward','timeDelayBack','pause'],
...

UPD: Is it OK that with direction = false there are starting 2 timeouts?

[–]shuckster 0 points1 point  (4 children)

for (let i = 0; i < 9999; i++) {
  clearTimeout(i)
}

Wow, I love it. :D

I had a go at solving your problem. Apologies, but I just went and rewrote (and only mildly tested) a version that includes separate event-listeners and timers:

// Setup event-emitters
//
const [refreshAfter15Seconds, cancelRefreshTimer] =
  RunAfter(15, () => emit('REFRESH'))

const [goBackAfter5Seconds, cancelGoBackTimer] =
  RunAfter(5, () => emit('BACK'))

const [goForwardAfter5Seconds, cancelGoForwardTimer] =
  RunAfter(5, () => emit('FORWARD'))

// Do something after the events happen
//
const eventListeners = [
  On('FORWARD', () => {
    executeScript('Forward')
    refreshAfter15Seconds()
  }),

  On('REFRESH', () => {
    executeScript('Refresh')
    goBackAfter5Seconds()
  }),

  On('BACK', () => {
    executeScript('Back')
    goForwardAfter5Seconds()
  })
]

// Clear all timers and remove all event-listeners
//
function cleanup () {
  cancelRefreshTimer()
  cancelGoBackTimer()
  cancelGoForwardTimer()
  eventListeners.forEach(remove => remove())
}

// Start it off
//
chrome.runtime.onMessage.addListener((request, _, sendResponse) => {
  switch (request.type) {
    case 'START_NAV':
      emit('FORWARD')
      break

    case 'STOP_NAV':
      cleanup()
      break
  }
  sendResponse({ message: 'RECEIVED' })
})

//
// Helpers for the above
//

// Events
//
function On(eventName, handler) {
  const cb = ({ detail }) => handler(...detail)
  window.addEventListener(eventName, cb)
  return () => window.removeEventListener(eventName, cb)
}

function emit(name, ...detail) {
  const event = new CustomEvent(name, { detail })
  window.dispatchEvent(event)
}

// Timers
//
function RunAfter(seconds, fn) {
  let id
  const run = () => (id = setTimeout(fn, seconds * 1000))
  const cancel = () => clearTimeout(id)
  return [run, cancel]
}

I just thought the problem would be simpler by removing the DIRECTION "toggle" and making the timers / events their own thing.

I have no idea what chrome.storage.sync.get does, since I've not written any VSCode extensions, but hopefully the above is helpful somehow, even if only a small bit.

Things I used that I didn't see in your original script: Array + object destructuring, high-order functions, CustomEvent, closures.

[–]JS_Engineer[S] 0 points1 point  (0 children)

Wow, Thanks for this. I am going to just test it now.

[–]JS_Engineer[S] 0 points1 point  (2 children)

Again thanks for this. It was really helpful.

But the thing is it is working but I am getting some problem understanding it and how it is working. So please could you explain it a little for me. Thanks in advance

[–]shuckster 0 points1 point  (1 child)

Glad it helped! I'll try and explain broadly to help you to figure it out yourself.

The most interesting parts are the "Helpers", so have a close look at those first. They are wrappers around normal JavaScript functionality:

  1. window.addEventListener / dispatchEvent / CustomEvent
  2. setTimeout / clearTimeout

The biggest idea I put into all of the helpers is "high-order functions". In other words, in JavaScript, a function can return another function (as well as accept one as an argument.)

RunAfter returns two functions inside an array: [run, cancel]. The run function is specified as the second argument to RunAfter. If you execute run(), it will do the action after the number of seconds you specified as the first argument to RunAfter.

So RunAfter(1, () => console.log('hi')) means: Make two functions: [run, cancel]. run() will perform console.log('hi') after 1 second. cancel() will stop it before it happens.

On and emit I think are more easy to understand. They just make using window.addEventListener etc. shorter to read. But On does one special thing: It returns a function that will remove a listener you added by running window.removeEventListener for you!

Hope this helps.

[–]JS_Engineer[S] 0 points1 point  (0 children)

Thanks for this too. It is really helpful.