【问题标题】:Recursive new Promise: RangeError: Maximum call stack size exceeded递归新承诺:RangeError:超过最大调用堆栈大小
【发布时间】:2018-03-02 02:10:39
【问题描述】:

我收到 RangeError:超出最大调用堆栈大小

function getUser(userId) {
    return new Promise((resolve, reject) => {
      controller.storage.users.get(userId, function(err, user) {
        if (err) reject(err);

        if (user) {
          if(!(user.orderData.pendingItem)) {
            getUser(userId)
          }
          else {
            resolve(user.orderData.pendingItem);
          }
        }
      })
    })
  };

我遇到的困境是,每当我运行controller.storage.users.get 时,它并不总是立即解析用户对象的所有属性和值,这就是为什么如果orderData.pendingItem 不是,我会尝试再次运行它那里。

但是,我猜是因为它运行了很多次,所以它给了我一个调用堆栈错误。

解决此问题或解决此问题的最佳方法是什么?

【问题讨论】:

  • 这看起来像一个被用作锤子的手机。当然,更好的解决方案是等待设置user.orderData.pendingItem 完成。至少,为此添加某种延迟。
  • 即使你让它工作了,你也基本上做了一个while(true),但它是递归的。最好将 pendingItem 设为一个承诺,无论它被填充在哪里,然后在您的代码中您就可以解决它。这样您就不会在等待完成时创建调用堆栈。
  • @ug_ 我同意你的评论。但是我目前的问题是所有数据都存储在内存中,而userorderData 实际上应该存储在数据库中,以便我可以在查询上做出承诺。但是,在我获得批准继续使用数据库之前,我几乎被困住了。

标签: javascript node.js promise callstack botkit


【解决方案1】:

理想情况下,您应该监听某个事件而不是轮询,但要了解这是一种临时解决方法...

new Promise() 同步运行它的构造函数,看起来controller.storage.users.get() 也同步运行它的回调。通过强制进行递归getUser() 调用异步可以避免“超出最大调用堆栈大小”的可能性,而最简单的方法是链接new Promise().then(/* recurse from here */)

function getUser(userId) {
    return new Promise((resolve, reject) => {
        controller.storage.users.get(userId, function(err, user) {
            if (err) reject(err);
            if (!user) reject(new Error('no user for id: ' + useId)); // this branch needs to be catered for
            resolve(user); // make `user` available to the .then() below
        });
    }).then(function(user) {
        return (user.orderData && user.orderData.pendingItem) || getUser(userId); // compact and safe
    });
}

这应该可以完成工作,但如果没有“最大调用堆栈大小”保护措施,很有可能会无缘无故地烧毁一两个处理器。

正如上面 cmets 所建议的,您可以并且可能应该在递归中添加一些延迟:

function delay(t) {
    return new Promise(function(resolve) {
        setTimeout(resolve, t);
    });
}

function getUser(userId) {
    return new Promise((resolve, reject) => {
        controller.storage.users.get(userId, function(err, user) {
            if (err) reject(err);
            if (!user) reject(new Error('no user for id: ' + useId)); // this branch needs to be catered for
            resolve(user); // make `user` available to the .then() below
        });
    }).then(function(user) {
        return (user.orderData && user.orderData.pendingItem) || delay(200).then(function() { // adjust the delay to maximum acceptable value
            return getUser(userId);
        });
    });
}

【讨论】:

    猜你喜欢
    • 2018-01-24
    • 2021-07-24
    • 2018-11-07
    • 1970-01-01
    • 2015-02-06
    • 1970-01-01
    • 2014-08-19
    • 1970-01-01
    • 2021-10-24
    相关资源
    最近更新 更多