我正在开发一个JS简单项目,需要从2个服务获取json结果(通过fetch()或XHR)。第一个是主要服务,第二个是后备。他们每个人都比另一个慢(提示:它是一个字典应用程序,2个服务是维基词典和谷歌翻译)。
为了获得更快的速度,我认为如果我异步(并行)获得两个结果会更好。它仍然更喜欢服务#1的结果,无论是快还是慢,并忽略(或中止)服务#2的任务。
但是如果它没有得到服务#1的结果,那么服务#2的结果将被用作替代。并且因为两个服务并行运行(从一个时间点开始),所以服务#2的结果可以尽快返回。
请在此处查看我的伪示例。
const setTimeOutP = (time, label, re = false) => {
return new Promise((resolve, reject) => {
setTimeout(function(){
if(re == false)
resolve(label);
else
reject(label);
},time);
});
};
promiseOneMustBeReturnedUnlessReject([setTimeOutP(1000, "promise 1"), setTimeOutP(3000, "promise 2")]); // Promise 1 (in 1s), similar to Promise.race
promiseOneMustBeReturnedUnlessReject([setTimeOutP(3000, "promise 1"), setTimeOutP(1000, "promise 2")]); // Promise 1 (in 3s)
promiseOneMustBeReturnedUnlessReject([setTimeOutP(1000, "promise 1", true), setTimeOutP(3000, "promise 2")]); // Promise 2 (in 3s), NOT 4s
promiseOneMustBeReturnedUnlessReject([setTimeOutP(4000, "promise 1", true), setTimeOutP(2000, "promise 2")]); // Promise 2 (in 4s), NOT 6s
promiseOneMustBeReturnedUnlessReject([setTimeOutP(4000, "promise 1", true), setTimeOutP(2000, "promise 2", true)]); // Reject in 4s
我现在有一个肮脏的解决方案,我认为它会像我描述的那样工作:
const printResult = async (key) => {
let dataObj = {
wiktionary: {
status: "pending"
},
googleTranslate: {
output: "",
status: "pending"
}
};
wiktionary(key).then(result => {
document.getElementById("result").innerHTML = result;
dataObj.wiktionary.status = "printed";
}).catch((error) => {
if (dataObj.googleTranslate.status == "ready") {
document.getElementById("result").innerHTML = dataObj.googleTranslate.output;
} else if (dataObj.googleTranslate.status == "error") {
throw new Error(error);
} else {
dataObj.wiktionary.status = "error";
}
});
googleTranslate(key).then(result => {
if (dataObj.wiktionary.status == "error") {
document.getElementById("result").innerHTML = result;
dataObj.googleTranslate.status = "printed";
} else {
dataObj.googleTranslate.output = result;
dataObj.googleTranslate.status = "ready";
}
}).catch((error) => {
if (dataObj.wiktionary.status == "error") {
throw new Error(error);
} else {
dataObj.googleTranslate.status = "error";
}
});
};
但有没有更优雅的方法来处理这种情况?
答案 0 :(得分:2)
您可以启动两个承诺,然后在出现错误时返回后备:
const translate = key => {
const fallback = googleTranslate(key);
return wiktionary(key)
.catch(() => fallback);
};
使用如下:
const printResult = async key => {
const result = await translate(key);
document.getElementById("result").innerHTML = result;
};
如果您有取消机制,请在.then()
之前的.catch()
中使用它。
答案 1 :(得分:1)
您不必立即将.then
处理程序置于承诺上 - 您可以等到他们需要时。如果在您将新.then
放在其上时已经解决了承诺,则新的.then
将立即运行。
const printResult = (key) => {
const googleProm = googleTranslate(key);
const resultElm = document.getElementById("result");
wiktionary(key)
.then(mainResult => resultElm.textContent = mainResult)
.catch((mainError) => {
googleProm.then(googleResult => resultElm.textContent = googleResult)
.catch(googleError => throw new Error(error));
});
};