简体   繁体   English

异步运行两个promise,但优先考虑第一个promise的结果

[英]Run two promises asynchronously, but prioritize the result of the first promise

I'm developing an JS simple project that requires taking the json result (via fetch() or XHR) from 2 services. 我正在开发一个JS简单项目,需要从2个服务中获取json结果(通过fetch()或XHR)。 The first is the main service, and the second acts as a fallback. 第一个是主要服务,第二个充当后备。 Each of them can be slower than the other (hint: it's a dictionary app, and 2 service is Wiktionary and Google Translate). 它们每个都可能比另一个慢(提示:这是一个字典应用程序,其中2个服务是Wiktionary和Google Translate)。

To get a little faster speed, I'm thinking it would be better if I get both of the results asynchronously (in parallel). 为了获得更快的速度,我认为如果异步(并行)获得两个结果会更好。 It still prefer the result of service #1 whether it's fast or slow, and ignore (or abort) the service #2's task. 无论速度是快还是慢,它仍然更喜欢服务1的结果,而忽略(或中止)服务2的任务。

But if it failed to get the result of service #1, then the result of service #2 will be used as alternative. 但是,如果未能获得服务1的结果,则将服务2的结果用作替代。 And because both services are run in parallel (from one point of time), service #2's result can be returned as fast as possible. 并且由于两个服务都是并行运行的(从一个时间点开始),因此可以尽快返回服务2的结果。

Please see my pseudo example here. 请在这里查看我的伪示例。

 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 

I have a dirty solution right now that I think it would work like I described: 我现在有一个肮脏的解决方案,我认为它可以像我描述的那样工作:

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";
        }
    });
};

But is there any more elegant way to handle this situation? 但是,有没有更优雅的方式来处理这种情况呢?

You can start both promises, then return the fallback in case of error: 您可以启动两个promise,然后在发生错误的情况下返回后备:

const translate = key => {
    const fallback = googleTranslate(key);

    return wiktionary(key)
        .catch(() => fallback);
};

used as follows: 用法如下:

const printResult = async key => {
    const result = await translate(key);
    document.getElementById("result").innerHTML = result;
};

If you have a cancellation mechanism, use it in a .then() before the .catch() . 如果你有一个取消机制,使用它的.then()的前.catch()

You don't have to put .then handlers on promises immediately - you can wait until they're necessary. 您不必立即将.then处理程序置于promise中-您可以等到必要时再使用它们。 If the promise has already been resolved by the time you put the new .then on it, the new .then will run immediately. 如果承诺在您将新.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));
    });
  };

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM