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.
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;
});
}
Veuillez vérifier ci-dessous que l'exemple retournerafactorial
d'un nombre donné, comme nous l'avons fait dans de nombreux langages de programmation.
J'ai implémenté l'exemple ci-dessous en utilisantJavaScript
promises.
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);
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'));