如何避免使用JavaScript中的回调进行堆栈蠕变?

时间:2018-10-09 00:43:03

标签: javascript callback stack

以下JavaScript代码模拟用户在window.alert上按下OK按钮时重试HTTP请求的频率。可以看出,转储到控制台的堆栈跟踪的长度随着请求重试次数的增加而线性增加。

要运行此命令,请使用chromium --user-data-dir=/tmp/"$(uuidgen -r)" --disable-web-security并导航至HTML文件,该文件仅包含最低限度的<html> <body><script>标签。要成功执行HTTP请求,必须禁用网络安全性,否则默认的CORS策略将阻止它。

基本上,问题是:如何防止线性堆叠蠕变?

function f() {
    console.log("C");
    fetch('http://swapi.co/api/films').
        then(function (response) {
            console.log("D");
            return response.json();
        }).then(function (response) {
            console.log("E");
            console.log(response);
            console.trace();
            window.alert("more?");
            f();
        });
}

function ignition() {
    console.log("B");
    f();
}

console.log("A");
window.onload = ignition;

1 个答案:

答案 0 :(得分:0)

找到了解决方案;这不理想,因为它涉及setInterval,但是它是可行的,并且避免了堆栈蠕变。它只能直接重试;尽管添加起来并不难,但是该解决方案不能在队列函数调用之间保持任何额外状态。

const self_queue = [];

function self_append(fun) {
    self_queue.push(fun);
}

setInterval((function() {
    if (self_queue.length > 0) {
        const fun = self_queue.shift();

        fun(fun);
    }
}), 100);

function ajax(url, fun) {
    self_append((function (self_fun) {
      // ...
      // do the HTTP fetch, on success call fun(json)
      // on retry, do:
      self_append(self_fun);
      // ....
    }));
}