Promesse récursive en javascript

j'écris un Javascript Promise qui trouve L'URL de redirection finale d'un lien.

ce que je fais c'est faire un HEAD demande Promise à l'aide d'un XMLHttpRequest. Puis, en charge, vérifiez L'état HTTP pour quelque chose dans la gamme 300, ou si elle a un responseURL attaché à l'objet et cette url est différente de celle qu'il a reçue d'une seule main.

si ni l'un ni l'autre n'est vrai, 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;
}

alors pour utiliser cette fonction je fais quelque chose comme:

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

Le problème est que resolve();getRedirectUrl appel then() à partir de la fonction d'appel avant d'appeler le getRedirectUrl appel récursif, et à ce point, L'URL est undefined.

j'ai essayé, plutôt que p.then(...getRedirectUrl...) en faisant return self.getRedirectUrl(...) mais cela ne résoudra jamais.

mon avis est que le modèle que j'utilise (que je essentiellement venu avec à la volée) n'est pas bonne, tout à fait.

19
demandé sur dfoverdx 2015-03-13 00:39:40

2 réponses

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

Pour résoudre ce problème:

Créer une promesse qui résout redirectUrl pour la 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();
});

Utiliser .then() pour retourner l'appel récursif, ou pas, en tant que de besoin:

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;
    });
}
28
répondu JLRishe 2016-06-07 20:49:23

veuillez cocher l'exemple ci-dessous il retournera factorial d'un nombre donné comme nous l'avons fait dans de nombreux langages de programmation.

j'ai implémenté l'exemple suivant en utilisant JavaScript promesses.

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);
1
répondu Mayur Shedage 2018-07-27 14:40:42