DOM Node Walker with Skip

I saw this code snippet from Caleb Porzio recently and I thought it used a very clever method to allow skipping nodes.

function walk(el, callback) {
  let current = el.firstElementChild

  while (current) {
    let skip = false
    callback(current, () => skip = true)
    skip || walk(current, callback)
    current = node.nextElementSibling
  }
}

The second most interesting part is on line 7 which uses the logical OR operator to only call walk() if skip is false.

The most interesting part is on line 6. At first it may seem that skip is set to true but in reality the callback function is called with two arguments:

  • current – the current node that the walker is on
  • an anonymous function that, if called, will set skip to true

This is a pattern that I’ve seen Caleb talk about before. Rather than passing state around, pass a function that when called will change state for you. This keeps the state management logic right next to where the state is actually used.

Here’s an example callback that demonstrates what is going on.

function callback(current_el, dontWalkNode) {
  // Skip walking children of current_el if it has class "skippable" (contrived)
  if ( current_el.classList.contains('skippable') ) {
    dontWalkNode()
    return
  }

  // More processing of current_el
}

In “real” code I’d probably simply return the result from dontWalkNode() to exit the callback but I didn’t in this case because I want to be totally clear that the result of the dontWalkNode() function doesn’t matter; what matters is that we simply call dontWalkNode() which changes the value of skip in the walk function.