web-dev-qa-db-fra.com

Promesse récursive en javascript

J'écris une Promise Javascript qui trouve l'URL de redirection finale d'un lien.

Ce que je fais est de faire une requête HEAD dans une Promise en utilisant une XMLHttpRequest. Ensuite, lors du chargement, recherchez dans l'état HTTP un élément compris dans la plage 300 ou si l'attribut responseURL est associé à l'objet et si cette URL est différente de l'adresse à laquelle il a été attribué. 

Si aucune de celles-ci n'est vraie, je resolve(url). Sinon, j'appelle récursivement getRedirectUrl() sur l'URL de la réponse et resolve().

Voici mon code:

function getRedirectUrl(url, maxRedirects) {
    maxRedirects = maxRedirects || 0;
    if (maxRedirects > 10) {
        throw new Error("Redirected too many times.");
    }

    var xhr = new XMLHttpRequest();
    var p = new Promise(function (resolve) {
        xhr.onload = function () {
            var redirectsTo;
            if (this.status < 400 && this.status >= 300) {
                redirectsTo = this.getResponseHeader("Location");
            } else if (this.responseURL && this.responseURL != url) {
                redirectsTo = this.responseURL;
            }

            if (redirectsTo) {
                // check that redirect address doesn't redirect again
                // **problem line**
                p.then(function () { self.getRedirectUrl(redirectsTo, maxRedirects + 1); });
                resolve();
            } else {
                resolve(url);
            }
        }

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

    return p;
}

Ensuite, pour utiliser cette fonction, je fais quelque chose comme:

getRedirectUrl(myUrl).then(function (url) { ... });

Le problème est que resolve(); dans getRedirectUrl appellera la then() à partir de la fonction appelante avant d'appeler l'appel récursif getRedirectUrl et qu'à ce stade, l'URL est undefined.

J'ai essayé, plutôt que p.then(...getRedirectUrl...) de faire return self.getRedirectUrl(...) mais cela ne résoudra jamais.

Mon hypothèse est que le modèle que j'utilise (que j'ai essentiellement créé à la volée) n'est pas correct, dans l'ensemble.

22
dx_over_dt

Le problème est que la promesse que vous retournez de getRedirectUrl() doit inclure toute la chaîne de logique pour accéder à l'URL. Vous retournez juste une promesse pour la toute première demande. Le .then() que vous utilisez au milieu de votre fonction ne fait rien.

Pour résoudre ce problème: 

Créez une promesse résolue en redirectUrl pour une redirection, ou rien sinon:

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

    xhr.onload = function () {
        var redirectsTo;

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

        resolve(redirectsTo);
    };

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

Utilisez .then() sur that pour renvoyer l’appel récursif ou non, selon vos besoins:

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

Solution complète:

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 () {
            var redirectsTo;

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

            resolve(redirectsTo);
        };

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

Veuillez vérifier ci-dessous que l'exemple retournerafactoriald'un nombre donné, comme nous l'avons fait dans de nombreux langages de programmation.

J'ai implémenté l'exemple ci-dessous en utilisantJavaScriptpromises.

let code = (function(){
	let getFactorial = n =>{
		return new Promise((resolve,reject)=>{
			if(n<=1){
				resolve(1);
			}
			resolve(
				getFactorial(n-1).then(fact => {
					return fact * n;
				})
			)
		});
	}
	return {
		factorial: function(number){
			getFactorial(number).then(
				response => console.log(response)
			)
		}
	}
})();
code.factorial(5);
code.factorial(6);
code.factorial(7);

3
Mayur Shedage

Voici la solution simplifiée:

const recursiveCall = (index) => {
    return new Promise((resolve) => {
        console.log(index);
        if (index < 3) {
            return resolve(recursiveCall(++index))
        } else {
            return resolve()
        }
    })
}

recursiveCall(0).then(() => console.log('done'));
0
cuddlemeister