Q:

What is the difference in following pattern to call recursive JavaScript function which returns a promise?

In following code with 100000 records recursiveFnReturnsPromiseV1 executes fine while recursiveFnReturnsPromiseV2 fails with out of stack exception. The only difference between two is the way promises are being recursed. In the v1, the recursion is within a "then" of the first promise while in v2, the recursion is within the original promise itself. What's the difference?

let aValues = Array(100000);


recursiveFnReturnsPromiseV1(aValues, 0).then(function() {
  let p = document.createElement('div');
  p.innerText = 'recursiveFnReturnsPromiseV1 finished';
  document.getElementById('v1').appendChild(p);
}, function() {
  let p = document.createElement('div');
  p.innerText = 'recursiveFnReturnsPromiseV1 failed';
  document.getElementById('v1').appendChild(p);
})

recursiveFnReturnsPromiseV2(aValues, 0)
  .then(function() {
    let p = document.createElement('div');
    p.innerText = 'recursiveFnReturnsPromiseV2 finished';
    document.getElementById('v2').appendChild(p);
  }, function() {
    let p = document.createElement('div');
    p.innerText = 'recursiveFnReturnsPromiseV2 failed';
    document.getElementById('v2').appendChild(p);
  })

function recursiveFnReturnsPromiseV1(pValues, ix) {
  if (pValues.length <= ix)
    return Promise.resolve();

  return new Promise(function(c, e) {
    document.getElementById('v1').innerText = ix + 'v1' + Date.now();
    c();
  }).then(function() {
    return recursiveFnReturnsPromiseV1(pValues, ++ix);
  })



}

function recursiveFnReturnsPromiseV2(pValues, ix) {
  if (pValues.length <= ix)
    return Promise.resolve();


  return new Promise(function(c, e) {
    document.getElementById('v2').innerText = ix + 'v2' + Date.now();

    recursiveFnReturnsPromiseV2(pValues, ++ix).then(function() {
      c();
    }, function(err) {
      e()
    });
  })
}
<div id='v1'></div>
<div id='v2'></div>

A:

Lets strip away the Promise constructor antipattern, and use a simple Promise.resolve instead. Your functions now become
function recursiveFnReturnsPromiseV1(pValues, ix) {
  if (pValues.length <= ix)
    return Promise.resolve();

  let p = document.createElement('div');
  p.innerText = ix + 'v1' + Date.now();
  document.getElementById('v1').appendChild(p);

  return Promise.resolve().then(function() {
    return recursiveFnReturnsPromiseV1(pValues, ++ix);
  })
}

function recursiveFnReturnsPromiseV2(pValues, ix) {
  if (pValues.length <= ix)
    return Promise.resolve();

  let p = document.createElement('div');
  p.innerText = ix + 'v2' + Date.now();
  document.getElementById('v2').appendChild(p);

  return Promise.resolve(recursiveFnReturnsPromiseV2(pValues, ++ix));
}

It should be obvious by now why the second function overflows the stack.
Why doesn't the first as well? Because the recursive call is inside an asynchronous then callback, which means it starts later (after the outer call returned) with a fresh call stack.

