我有一个我希望获取的网址列表。所有这些url都返回一个带有属性valid
的json对象。但是只有一个获取承诺具有valid
的神奇true
属性。
我尝试了url.forEach(...)
和Promises.all([urls]).then(...)
的各种组合。目前我的设置是:
const urls = [
'https://testurl.com',
'https://anotherurl.com',
'https://athirdurl.com' // This is the valid one
];
export function validate(key) {
var result;
urls.forEach(function (url) {
result = fetch(`${url}/${key}/validate`)
.then((response) => response.json())
.then((json) => {
if (json.license.valid) {
return json;
} else {
Promise.reject(json);
}
});
});
return result;
}
由于异步承诺,上述方法无法正常工作。如何在第一个valid == true
被击中时迭代我的网址并返回?
答案 0 :(得分:3)
让我在混合中输入一个很好的紧凑条目
它使用Promise.all,但是在这种情况下,每个内部Promise都会捕获任何错误并简单地解析为false
,因此Promise.all永远不会拒绝任何完成但没有许可的提取。有效也将解析为false
进一步处理数组Promise.all resolves,过滤掉false
值,并返回第一个(来自问题描述应该是唯一的)有效的JSON响应
const urls = [
'https://testurl.com',
'https://anotherurl.com',
'https://athirdurl.com' // This is the valid one
];
export function validate(key) {
return Promise.all(urls.map(url =>
fetch(`${url}/${key}/validate`)
.then(response => response.json())
.then(json => json.license && json.license.valid && json)
.catch(error => false)
))
.then(results => results.filter(result => !!result)[0] || Promise.reject('no matches found'));
}
答案 1 :(得分:1)
请注意,validate
无法返回结果(see here for why)。但它可以为结果返回 promise 。
你想要的是类似到Promise.race
,但不完全相同(Promise.race
会拒绝其中一个fetch
承诺在另一个承诺之前被拒绝用valid = true
解析。因此,当您获得valid
为真的第一个分辨率时,只需创建一个承诺并解决它:
export function validate(key) {
return new Promise((resolve, reject) => {
let completed = 0;
const total = urls.length;
urls.forEach(url => {
fetch(`${url}/${key}/validate`)
.then((response) => {
const json = response.json();
if (json.license.valid) {
resolve(json);
} else {
if (++completed === total) {
// None of them had valid = true
reject();
}
}
})
.catch(() => {
if (++completed === total) {
// None of them had valid = true
reject();
}
});
});
});
}
请注意失败案例的处理。
请注意,如果您愿意,可以将这两个completed
检查分解出来:
export function validate(key) {
return new Promise((resolve, reject) => {
let completed = 0;
const total = urls.length;
urls.forEach(url => {
fetch(`${url}/${key}/validate`)
.then((response) => {
const json = response.json();
if (json.license.valid) {
resolve(json);
}
})
.catch(() => {
// Do nothing, converts to a resolution with `undefined`
})
.then(() => {
// Because of the above, effectively a "finally" (which we
// may get on Promises at some point)
if (++completed === total) {
// None of them had valid = true.
// Note that we come here even if we've already
// resolved the promise -- but that's okay(ish), a
// promise's resolution can't be changed after it's
// settled, so this would be a no-op in that case
reject();
}
});
});
});
}
答案 2 :(得分:0)
可以使用SynJS完成此操作。这是一个有效的例子:
var SynJS = require('synjs');
var fetchUrl = require('fetch').fetchUrl;
function fetch(context,url) {
console.log('fetching started:', url);
var result = {};
fetchUrl(url, function(error, meta, body){
result.done = true;
result.body = body;
result.finalUrl = meta.finalUrl;
console.log('fetching finished:', url);
SynJS.resume(context);
} );
return result;
}
function myFetches(modules, urls) {
for(var i=0; i<urls.length; i++) {
var res = modules.fetch(_synjsContext, urls[i]);
SynJS.wait(res.done);
if(res.finalUrl.indexOf('github')>=0) {
console.log('found correct one!', urls[i]);
break;
}
}
};
var modules = {
SynJS: SynJS,
fetch: fetch,
};
const urls = [
'http://www.google.com',
'http://www.yahoo.com',
'http://www.github.com', // This is the valid one
'http://www.wikipedia.com'
];
SynJS.run(myFetches,null,modules,urls,function () {
console.log('done');
});
它会产生以下输出:
fetching started: http://www.google.com
fetching finished: http://www.google.com
fetching started: http://www.yahoo.com
fetching finished: http://www.yahoo.com
fetching started: http://www.github.com
fetching finished: http://www.github.com
found correct one! http://www.github.com
done
答案 3 :(得分:-1)
如果您想避免测试每个网址,可以使用以下代码。
For Each item In fol.Items
If item.IsFolder Then
Set fol2 = item.GetFolder
ProcessFolderRecursively fol2, row
Else
Sheets("Sheet2").Select
Cells(row, 1) = item.path
row = row + 1
End If
Next