递归新Promise:RangeError:超出最大调用堆栈大小

时间:2017-09-20 21:08:55

标签: javascript node.js promise callstack botkit

我收到了一个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时,它并不总能立即解析用户对象的所有属性和值,这就是为什么我尝试再次运行它{{1 }} 不在这里。

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

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

1 个答案:

答案 0 :(得分:2)

理想情况下,你应该倾听一些事件而不是轮询,但是要理解这是一个临时的解决方法......

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

这应该可以完成这项工作,但如果没有“最大调用堆栈大小”的保护措施,那么就很有可能在没有充分理由的情况下煎炸一两个处理器。

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

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