Recursive Promise in javascript

The problem is that the promise you return from getRedirectUrl() needs to include the entire chain of logic to get to the URL. You’re just returning a promise for the very first request. The .then() you’re using in the midst of your function isn’t doing anything.

To fix this:

Create a promise that resolves to redirectUrl for a redirect, or null otherwise:

function getRedirectsTo(xhr) {
    if (xhr.status < 400 && xhr.status >= 300) {
        return xhr.getResponseHeader("Location");
    }
    if (xhr.responseURL && xhr.responseURL != url) {
        return xhr.responseURL;
    }

    return null;
}

var p = new Promise(function (resolve) {
    var xhr = new XMLHttpRequest();

    xhr.onload = function () {
        resolve(getRedirectsTo(xhr));
    };

    xhr.open('HEAD', url, true);
    xhr.send();
});

Use .then() on that to return the recursive call, or not, as needed:

return p.then(function (redirectsTo) {
    return redirectsTo
        ? getRedirectUrl(redirectsTo, redirectCount+ 1)
        : url;
});

Full solution:

function getRedirectsTo(xhr) {
    if (xhr.status < 400 && xhr.status >= 300) {
        return xhr.getResponseHeader("Location");
    }
    if (xhr.responseURL && xhr.responseURL != url) {
        return xhr.responseURL;
    }

    return null;
}

function getRedirectUrl(url, redirectCount) {
    redirectCount = redirectCount || 0;

    if (redirectCount > 10) {
        throw new Error("Redirected too many times.");
    }

    return new Promise(function (resolve) {
        var xhr = new XMLHttpRequest();

        xhr.onload = function () {
            resolve(getRedirectsTo(xhr));
        };

        xhr.open('HEAD', url, true);
        xhr.send();
    })
    .then(function (redirectsTo) {
        return redirectsTo
            ? getRedirectUrl(redirectsTo, redirectCount + 1)
            : url;
    });
}

Leave a Comment