【问题标题】:What is the difference in following pattern to call recursive JavaScript function which returns a promise?以下模式调用返回承诺的递归 JavaScript 函数有什么区别?
【发布时间】:2017-12-05 00:29:49
【问题描述】:

在以下包含 100000 条记录的代码中,recursiveFnReturnsPromiseV1 执行良好,而 recursiveFnReturnsPromiseV2 因堆栈异常而失败。两者之间的唯一区别是 promise 的递归方式。在 v1 中,递归在第一个 Promise 的“then”内,而在 v2 中,递归在原始 Promise 本身内。有什么区别?

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>

【问题讨论】:

  • v1,递归是异步完成的(它在 .then 中)...... v2 递归不是...... Promise 构造函数中的代码是同步的......注意:你的代码是由于看似随机的缩进而难以阅读
  • 你真的发现每一级只使用一个缩进空格的代码是可读的吗?我不。读不出来。无法理解,如此处所示。不会花时间在代码难以阅读的问题上。
  • @jfriend00 - 如果您查看recursiveFnReturnsPromiseV2 函数,甚至不是这样,第一个代码缩进 4 .. 然后返回缩进 2,然后承诺执行程序的第一行是也缩进 2,然后接下来的两行缩进 1,因此相对于它们所在的块“缩进”1 ...正如我提到的,它实际上是非常随机的(尽管很容易复制/粘贴到 firefox暂存器并修复:p)
  • @JaromandaX - 这里有很多问题我们可以花时间解决。如果 OP 不打算让他们的问题可读,那么我可能会花时间在那些做的事情上。是的,我可以将代码复制到某处(比如复制到代码格式化程序中)以使其可读(有时我会这样做),但我向 OP 提供了一些建议,说明如何让他们的问题更有吸引力,让人们把时间花在.如果我们不提供反馈,他们就无法听到如果他们让他们的问题更容易处理,他们会获得更多帮助。
  • @jfriend00 公平的电话,我在阅读代码之前就猜到了问题的根源:p

标签: javascript recursion promise


【解决方案1】:

让我们去掉Promise constructor antipattern,改用简单的Promise.resolve。你的函数现在变成了

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));
}

现在应该很清楚为什么第二个函数会溢出堆栈。

为什么不是第一个呢?因为递归调用在 异步then 回调中,这意味着它稍后(在外部调用返回之后)使用新的调用堆栈开始。

【讨论】:

    猜你喜欢
    • 2019-05-25
    • 1970-01-01
    • 2020-01-24
    • 2023-03-28
    • 2017-05-09
    • 1970-01-01
    • 1970-01-01
    • 2015-12-05
    • 2012-12-24
    相关资源
    最近更新 更多