我正在写一个Javascript Promise
,它可以找到链接的最终重定向URL。
我所做的是使用XMLHttpRequest
在Promise
中发出HEAD
请求。然后,在加载时,检查HTTP状态是否在300范围内,或者是否有responseURL
附加到对象,并且该URL与单手操作时的URL不同。
如果这两个都不为真,则调用resolve(url)
,否则,在响应URL上递归调用getRedirectUrl()
,然后调用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;
}
为了使用这个函数,我做了如下操作:
getRedirectUrl(myUrl).then(function (url) { ... });
问题是getRedirectUrl
中的resolve();
在调用getRedirectUrl
递归调用之前将从调用函数调用then()
,此时,URL为undefined
。
我试过了,而不是p.then(...getRedirectUrl...)
做return self.getRedirectUrl(...)
,但这永远不会解决。
我的猜测是,我使用的模式(基本上是我匆忙想出的)完全不正确。
7条答案
按热度按时间bvk5enib1#
问题在于,从
getRedirectUrl()
返回的承诺需要包括到达URL的整个逻辑链,您只是返回了第一个请求的承诺,而在函数中间使用的.then()
没有做任何事情。要解决此问题:
创建解析为
redirectUrl
以进行重定向或解析为null
的承诺:根据需要,在 * that * 上使用
.then()
返回递归调用或不返回:完整解决方案:
7xllpg7q2#
以下是简化的解决方案:
0md85ypi3#
以下有两个功能:
秘密武器是子承诺,它的成功完成将触发父承诺调用resolve()。
作为递归Promises的另一个例子,我用它来解决一个迷宫。
Solve()
函数被递归调用来推进迷宫解决方案中的一个步骤,否则当它遇到死胡同时它会后退。setTimeout
函数被用来将解决方案的动画设置为每帧100ms(即10hz帧速率)。一个二个一个一个
rjee0c154#
请检查下面的示例,它将返回给定数字的**
factorial
,就像我们在许多编程语言中所做的那样。我已经使用
JavaScript
**承诺实现了下面的示例。hfsqlsce5#
如果您所在的环境支持
async
/await
(实际上所有现代环境都是这样),您可以编写一个async function
,它看起来更像是我们都知道并喜爱的递归函数模式,但由于XMLHttpRequest
只能通过load
事件检索值,因此不可能完全避免使用Promise
(而不是公开Promise
本身),但是进行调用的函数的递归性质应该看起来很熟悉。我的JavaScript经验比我最初写这个问题时多了四年,我稍微清理了一下代码,但它的工作方式基本上是一样的。
async
/await
的简要说明async function
是Promise
的语法糖await
是Promise.then()
的语法糖async function
中的return
是resolve()
的语法糖async function
中的throw
是reject()
的语法糖如果
async function
返回另一个async function
调用或Promise
,则函数/promise将在原始调用解析之前解析,与Promise
模式中解析Promise
的方式完全相同。因此,您可以按照与原始问题完全相同的方式调用
getRedirectUrl(someUrl).then(...).catch(...)
。应该注意的是,使用XHR解析重定向的URL对于任何不包含正确CORS头的URL都将失败。
作为一个额外的好处,async/await使迭代方法变得微不足道。
另一个注意事项:现代的浏览器有一个
fetch()
函数,它基本上做createXHRPromise()
所做的事情,但是更加通用。node不支持它,但是有一个npm包叫做node-fetch
。j5fpnvbx6#
请检查下面的例子中的递归承诺在javascript/typescript,它不会解决承诺,直到数字增加到大于13.
下面的代码适合于typescript,并针对javascript稍作修改。
nhjlsmyf7#
如果你有一个嵌套的数组结构,并且有异步调用,这个解决方案(建立在前面的答案之上)可能会有帮助。这个例子为它在一个(可能的)嵌套数组中找到的每个值运行一个setTimeout(),并在处理完所有的值后进行解析: