Hypertable
Hypertable

Reputation: 133

How to avoid stack creep with callbacks in javascript?

The following JavaScript code emulates retrying an HTTP request as often as the user presses the OK button on a window.alert. It can be seen that the stack trace dumped to the console increases in length linearly with the number of times the request retried.

To run this, use chromium --user-data-dir=/tmp/"$(uuidgen -r)" --disable-web-security and navigate to an HTML file that just contains the bare minimum <html> <body> and <script> tags. Disabling web security is required for the HTTP request to succeed, otherwise the default CORS policy will block it.

Basically, the question is: how can this linear stack creep be prevented?

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;

Upvotes: 0

Views: 57

Answers (1)

Hypertable
Hypertable

Reputation: 133

Found a solution; it's not ideal as it involves setInterval but it's workable and avoids stack creep. It can only do straight retry; this solution cannot maintain any extra state between invocations of the queued functions, though it wouldn't be that hard to add.

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

Upvotes: 1

Related Questions