A little while ago, I came across a feature in JavaScript I hadn’t seen before: Generator functions.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*

At first, I was perplexed at what these could be used for. Even still, I find it hard to find a use-case for JS generators. Why use a generator when X or Y would do the trick just fine? That question I still don’t have a exact answer for, but what I do have is some examples of where I was actually able to find use for these.

Use-Case 1: Iterate an Array with an Unknown length

So this has been my thought behind when should a generator be used. It first came up when I was tasked with retrieving all the entries from an API endpoint. This specific endpoint did not have a way to retrieve a count/total of how many items would need to be pulled. The endpoint however, did offer parameters for limit (how many items we want returned) and skip (how many items we want to ‘skip’ over). Using these, we could easily setup something to call it over and over, but we want to be a little smarter than that.

So to recap, our script needs to call and page through all the results the endpoint returns. Using generators, I created something like this:

function* itemFetcher() {
  let is_done = false
  const params = {
    limit: 20,
    skip: 0
  }

  const resolve = res => {
    const items = res.data
    if(!Array.isArray(items) && !items?.length) throw new Error(‘finished!’)
    params.skip += params.limit
    return items
  }

  while(!is_done) {
    yield axios.get(‘my-api.com/items’, { params })
      .then(resolve)
      .catch(err => {
        console.log(err)
        is_done = true
      })
  }
}

async function main() {
  for (const item_fetch of itemFetcher())
    const items = await item_fetch
    if (!items) break
    console.log(items)
  }
}

Calling the main function will start a “loop” which will call the api endpoint until it returns 0 items or errors out. The loop will wait for the api call to complete and if returns nothing, it breaks, otherwise it console logs the items.

One thing to note about this example is that the generator is yielding a promise, instead of being a promise itself. Generators can be async, but I find it more annoying to work with those.

Use-Case 2: A Queue System

Another use-case I found for generators was for a queue like system. To setup the example, let’s say we have a array called `processing` which contains a list of items that need to be handled in the order they were received.

const processing = [ thing1, thing2, thing3 ]

function* processQueue() {
  while (processing.length) {
    yield processing.shift()
  }
}

function main() {
  for (const item of processQueue()) 
    processing.push(item)
  }
}

In this example, calling main would create a infinite loop. This is because once the generator shifts the element out of the array, main pushes it right back in. The generator is watching the array’s length and would break when it’s empty, but that would never happen.

Conclusion

JavaScript generators are a interesting feature, but one I find hard to see a use-case for. They can be extremely handy, or a pain in your side. Maybe in the future I will find more use-cases for it, but maybe not everything needs 100 use-cases and the 2 I gave are plenty enough.


Use-Cases & Notes Presented by Commenters

https://crank.js.org

1 Comment

Some Use-Cases for JS Generator Functions - The web development company · September 2, 2021 at 12:02 pm

[…] submitted by /u/MichealPearce [link] [comments] Source: […]

Leave a Reply

%d bloggers like this: