问题描述
我正在编写一个 Javascript Promise
来查找链接的最终重定向 URL.
I'm writing a Javascript Promise
that finds the final redirect URL of a link.
我正在做的是使用 XMLHttpRequest
在 Promise
中发出一个 HEAD
请求.然后,在加载时,检查 HTTP 状态是否在 300 范围内,或者它是否具有附加到对象的 responseURL
并且该 url 与单手的不同.
What I'm doing is making a HEAD
request in a Promise
using an XMLHttpRequest
. Then, on load, check the HTTP Status for something in the 300 range, or if it has a responseURL
attached to the object and that url is different than the it was one handed.
如果这些都不对,我resolve(url)
.否则,我会在响应 URL 上递归调用 getRedirectUrl()
和 resolve()
.
If neither of these are true, I resolve(url)
. Otherwise, I recursively call getRedirectUrl()
on the response URL, and resolve()
.
这是我的代码:
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;
}
然后要使用此功能,我会执行以下操作:
Then to use this function I do something like:
getRedirectUrl(myUrl).then(function (url) { ... });
问题是getRedirectUrl
中的resolve();
会在调用之前从调用函数调用
递归调用,此时 URL 为 then()
>getRedirectUrlundefined
.
The issue is that resolve();
in getRedirectUrl
will call the then()
from the calling function before it calls the getRedirectUrl
recursive call, and at that point, the URL is undefined
.
我试过,而不是 p.then(...getRedirectUrl...)
做 return self.getRedirectUrl(...)
但这永远不会解决.
I tried, rather than p.then(...getRedirectUrl...)
doing return self.getRedirectUrl(...)
but this will never resolve.
我的猜测是我正在使用的模式(我基本上是即时想到的)完全不正确.
My guess is that the pattern I'm using (that I basically came up with on the fly) isn't right, altogether.
推荐答案
问题是你从 getRedirectUrl()
返回的 promise 需要包含整个逻辑链才能到达 URL.您只是为第一个请求返回一个承诺.您在函数中使用的 .then()
没有做任何事情.
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.
要解决这个问题:
为重定向创建一个解析为 redirectUrl
的承诺,否则为 null
:
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();
});
在 that 上使用 .then()
返回递归调用,或不返回,根据需要:
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;
});
完整解决方案:
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;
});
}
这篇关于javascript中的递归承诺的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!