How to re-run a javascript promise when failed?

2019-05-30 10:40发布

问题:

I have the following code where I am trying to convert a list of 10-15 addresses in the businesses array into lat/lng coordinates using Google Maps Geocoding API.

var geocoder = new google.maps.Geocoder();

var proms = businesses.map(function(address) {
    return prom = new Promise(function(resolve) {
       geocoder.geocode({
            address: address
        }, function(results, status) {

            if (status === google.maps.GeocoderStatus.OK) {
                resolve({
                    results: results,
                    business: address
                });

            } else if (status === google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
                setTimeout(function() {
                    //HOW DO I RE-RUN THIS "new Promise"?
                }, 1000);

            } else {
                console.log(status + ': ' + results);
            }

        });
    });
});
Promise.all(proms);

The problem is that Google's API will sometimes return an OVER_QUERY_LIMIT error so I was wondering if there's a way to re-run the promise that failed after a few seconds. In the example above the else if statement catches the error, so how would I make it rerun after a timeout?

Note that I just started using promises and don't have a good understanding yet how they work so my approach might be completely wrong. Also all of this is done under the assumption that Google's API won't let me resolve addresses in bulk, if that's not the case - please, let me know.

回答1:

You can put the main body of code into a function and call it again from the timer. Note: this is not technically rerunning a promise, it's rerunning a block of code that will then resolve the promise when done:

var proms = businesses.map(function(address) {
    return prom = new Promise(function(resolve, reject) {
        var retriesRemaining = 5;
        function run() {
            geocoder.geocode({
                    address: address
                }, function(results, status) {

                    if (status === google.maps.GeocoderStatus.OK) {
                        resolve({
                            results: results,
                            business: address
                        });

                    } else if (status === google.maps.GeocoderStatus.OVER_QUERY_LIMIT) {
                        --retriesRemaining;
                        if (retriesRemaining <= 0) {
                            reject(status);
                        } else {
                            setTimeout(run, 1000);
                        }
                    } else {
                        console.log(status + ': ' + results);
                    }

                }
            });
        }
        run();
    });
});
Promise.all(proms);

FYI, I also added a retry count so the code can never get stuck in an error loop.

You may also be interested in this post: How to avoid Google map geocode limit?.



回答2:

The one time I had this error it was because I was sending requests too quickly, put a wait for a second in there between each request.