Native JS Promise Retry Wrapper

六眼飞鱼酱① 提交于 2021-01-05 09:46:54

问题


Problem Overview: I have a GreaseMonkey/TamperMonkey script in FireFox that sends several GM_xmlhttpRequest (essentially similar to a xml http request, however this wrapper allows ease in cross-origin requests) to URL's to retrieve simple JSON data. Some of the JSON data retrieved is super simple, like so,

    {id:123459876, code:"frog"}
    [{value:"water", contents:0}]

This leads me to my outline of what code I've got down for my programming task so far, and, eventually shapes what I'll ask in the end as my question.

Problem Outline: Since the workflow I'm essentially doing is as follows; (based off this SO question/answer)

  1. Send a 'GET' request with GM_xmlhttpRequest inside a Promise object
function makeRequest(reqMethod, navURL) {
    return new Promise(function (resolve, reject) {
        GM_xmlhttpRequest({
            method: reqMethod,
            url:    navURL,
            onload: function () {
                if (this.status >= 200 && this.status < 300) {
                    resolve(this.response);
                } else {
                    reject({
                        status: this.status,
                        statusText: this.statusText
                    });
                }
            },
            onprogress: function(event) {
                console.log(`Loaded ${event.loaded} of ${event.total}`);
            },
            onerror: function(data) {
                reject({
                    status: this.status,
                    statusText: this.statusText
                });
            }
        });
    });
}
  1. Upon returning a successful status within the GM_xmlhttpRequest - the promise returns the JSON as the resolve response.
    function makeRequestWrapper(requestMethod, navToURL, successFunction) {
        makeRequest(requestMethod, navToURL)
            .then(
                function (datums) {
                    successFunction(datums);
                }
            )
            .catch(
                function (err) {
                    console.error('there was an error!', err.statusText);
                }
            );
    }
  1. Have the initial promise, upon success resolve, run a post processing function to update the current window page with the retrieved JSON data
// one of the 3 example handler methods for dealing with the success + JSON
    function successHandler1(jsonDataResponse) {
        let response = JSON.parse(jsonDataResponse);
        let id = response[0].id;
        let updateLink = document.getElementById("unique_link_id").parentNode.parentNode;
        updateLink .innerHTML += ` ID: ${id} `;
    }

Up until this point, my code works as I've intended, the Promise on success returns the JSON data and I update my current window page with that retrieved data.

However, my issue is that some users of the script that pulls this JSON data will have the Promise fail (some more frequently than others) - thus my next step of triage I'm attempting is retrying Promise's a certain number of times, and, with a delay. This way, I figure retrying a failed Promise, let's say 3 times, with 3 second delays, should give ample attempts and time to increase the success rate for the Promise.

My thoughts

Since I am a relative newbie to JS (still learning it and hopefully becomes a language I can use in life), I've read things like Promises and Observables? and rethink if I'm on the right path with this problem. I think I need an in-depth example, specific to my use case, and, with thorough step-by-step explanation, in order to learn more about not only Promises, but also this use-case scenario.

So far, I have attempted to integrate my working code with these SO answers about promises with retry, like:

  • Promise Retry Design Patterns
  • Generic promise retry logic
  • Retry on Javascript.Promise.reject a limited number of times or until success
  • Recursive retry in Promise
  • How to retry an xhr request which returns a promise recursively for atleast n times on status 0
  • Promises: Repeat operation until it succeeds?
  • general solution to retry a promise in javascript

As well as reading blog posts, like;

  • Retry Pattern in Node.js using Promise
  • JavaScript: Promises and Why Async/Await Wins the Battle
  • Retry Sync/Async(Promises) functions of Javascript

I've also looked at countless doc's, like;

  • https://developer.mozilla.org/en-US/docs/Web/API/
  • https://wiki.greasespot.net/
  • https://javascript.info/
  • https://devdocs.io/javascript/

And finally, some random (not as well structured) links;

  • gist example (tho somewhat incomplete)

Question

How do I go about converting my existing code to an aforementioned example, or, creating a new API-like method to handle my existing code (work around what I have)?


回答1:


Here's a wrapper around your makeRequest() function that lets you pass in the max retry count and the delay between retries. It returns a promise that resolves if successful or rejects if it still has an error after maxRetries.

function makeRequestRetry(requestMethod, navToURL, maxRetry = 3, retryDelay = 3000) {
    let retryCnt = 0;

    function delay(t) {
        return new Promise(resolve => {
            setTimeout(resolve, t);
        });
    }
    
    function run() {
        return makeRequest(requestMethod, navToURL).catch(function (err) {
            ++retryCnt;
            if (retryCnt > maxRetry) {
                console.error('Max retries exceeded. There was an error!', err.statusText);
                throw err;
            }
            console.error('Retry #' + retryCnt + ' after error', err.statusText);
            // call ourselves again after a short delay to do the retry
            // add to the promise chain so still linked to the originally returned promise
            return delay(retryDelay).then(run);
        });
        
    }
    return run();
}

And, one would call it like this:

makeRquestRetry('GET', someURL, 5, 5000).then(result => {
    console.log(result);
}).catch(err => {
    console.log(err);
});

Or, go with the default values for retry parameters:

makeRquestRetry('GET', someURL).then(result => {
    console.log(result);
}).catch(err => {
    console.log(err);
});


来源:https://stackoverflow.com/questions/57792389/native-js-promise-retry-wrapper

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!