0

I was playing around with recursion and looking at the benchmark of different implementation.

function plusOne(xs) {
  if (xs.length <= 0) return []
  return [xs[0], ...plusOne(xs.slice(1))]
}


function plusOne2(xs) {
  if (xs.length <= 0) return Promise.resolve([])
  return plusOne2(xs.slice(1)).then(result => [xs[0] + 1, ...result])
}

function plusOne3(xs, cb) {
  if (xs.length <= 0) return cb([])
  return plusOne3(xs.slice(1), result => cb([xs[0], ...result]))
}

I notice the performance improved in the second implementation when I simply wrap the result in promise. I wonder why would it be the case.

Also in the third implementation, shouldn't the browser be able to do tail call optimisation with this continuation passing style? Why is it the slowest instead?

See perf.link

Jason Yu
  • 311
  • 2
  • 12

2 Answers2

2

I notice the performance improved in the second implementation when I simply wrap the result in promise. I wonder why would it be the case.

Because you're not .then()ing the promise to finally resolve its value, so the .then() chain isn't called.

In other words: it's faster because it's not doing the work.

Also in the third implementation, shouldn't the browser be able to do tail call optimisation with this continuation passing style?

You assume your browser's JS engine can recognize it can do tail call optimisation there. For instance, what if your cb would require information on the call stack?

AKX
  • 152,115
  • 15
  • 115
  • 172
  • *"so the `.then()` chain isn't called."* This is not quite it. Promises are eager, holding computations that are already started. So it's not that this isn't called, simply that we don't wait for it before our function returns. There are libraries that create `Future`s or `Task`s that work the way you suggest. – Scott Sauyet Sep 06 '22 at 14:03
1

You are not waiting for those promises to finish.

Try this:

async function plusOne(xs) {
  if (xs.length <= 0) return []
  return [xs[0] + 1, ... await plusOne(xs.slice(1))]
}


await plusOne(xs)
Sergiu Paraschiv
  • 9,929
  • 5
  • 36
  • 47