2017-08-10 2 views
0

Ich muss die folgende Logik implementieren.So führen Sie Promise erneut aus, bis eine Bedingung

Ich muss ein Bild herunterladen, aber irgendwann passiert es, dass eine heruntergeladene Datei beschädigt ist, also muss ich versuchen, es erneut herunterzuladen. So sieht mein Download-Versprechen aus.

return Downloader.downloadImage(downloadUrl, fileName).then((filename) => { 
      // Update some info, save ... and return new promise 
      return doStuffAndReturnPromise(filename); 
     }); 

Aber wie ich beschrieben habe ich oben überprüfen müssen, ob die heruntergeladene Datei gültiges Bild ist und nur dann mit Erfolg zurückkehrt Versprechen.

Hier ist ein Skelett.

Das Problem hier ist, dass ich das Download-Versprechen synchron ausführen muss und nur dann weiter iterieren und ein neues Versprechen laufen.

Bitte schlagen Sie den besten Weg, um dieses Problem elegant zu lösen.

Danke.

+0

Verwenden Sie einen rekursiven Ansatz anstelle einer Schleife. – Bergi

+0

@Bergi könnten Sie bitte ein Beispiel geben – bxfvgekd

+0

[Hier] (https://stackoverflow.com/a/36135070/1048572) ist ein größeres Beispiel – Bergi

Antwort

1

können Sie nur ein Versprechen zurück, die wieder anstelle des answear versuchen, so etwas wie dieses:

Downloader.downloadImage(downloadUrl, fileName) 
.then(function(data) { 
    // Here your file is right 
}) 
.catch(function(err) { 
    // Here you tried 5 times and failed 
}) 
1

Ich schrieb dieses Beispiel eine Weile zurück:

var maxAttempts = 5 
var counter = 0 

return Downloader.downloadImage(downloadUrl, fileName).then((filename) => { 
    // Update some info, save ... and return new promise 
    if (checkIfNeedToTryAgain()) { 
     counter++; 
     if (counter > maxAttempts) { 
      throw maxAttemptsError 
     } 
     // Try again 
     return Downloader.downloadImage(downloadUrl, fileName) 
    } 
    // In case of success 
    return doStuffAndReturnPromise(filename); 
}); 

Sie es wie folgt verwenden könnte (http://jsbin.com/xefutos/6/edit?html,js,output), die Sie sollten in der Lage sein, für Ihre eigenen Bedürfnisse anpassen:

// Function that returns a promise 
var searchForNumber = function(number) { 
    return new Promise(function(resolve, reject) { 
     setTimeout(function() { 
     var min = 1; 
     var max = 10; 
     var val = Math.floor(Math.random()*(max-min+1)+min); 

     console.log('Value is: ' + val.toString());   

     return resolve(val);   
     }, 1000); 
    }); 
}; 

// fn  : function that should return a promise. 
// args : the arguments that should be passed to fn. 
// donefn : function that should check the result of the promise 
// and return true to indicate whether ploop should stop or not. 
// promise: A promise value that is used internally by ploop and should never 
// be passed in by the caller of ploop. 
var ploop = function(fn, args, donefn, promise) { 
    return (promise = promise || Promise.resolve(true))  
     .then(function() { 
      return(fn.apply(null, args)); 
     }) 
     .then(function(result) { 
     var finished = donefn(result); 
     if(finished === true){ 
      return result; 
     } else { 
      return ploop(fn, args, donefn, promise); 
     } 
    }); 
}; 

var searchFor = 4; 

var donefn = function(result) { 
    return result == searchFor; 
}; 

console.log('Searching for: ' + searchFor); 
ploop(searchForNumber, [searchFor], donefn) 
    .then(function(val) { 
    console.log('Finally found! ' + val.toString()); 
    process.exit(0); 
    }) 
    .catch(function(err) { 
    process.exit(1); 
    }); 
1

Ich finde das Observer-Muster in solchen Szenarien sehr hilfreich, da es Code lesbarer und wiederverwendbar macht. Hier ist, wie der Code aussehen könnte

Oben ist der Code zum Download. IMO, es ist auch in Zukunft wieder verwendbar oder hat andere Beobachter, die darauf reagieren.

const MyObservable = require('./MyObservable'); 

const observable = new MyObservable(); 


let retryCount = 3; 
observable.on('done', (message) => { 
    console.log('Download completed'); 
}); 
observable.on('error', (message) => { 
    retryCount -= 1; 
    if (retryCount > 0) { 
    observable.downloadImage(imageUrl); 
    } 
}); 
observable.downloadImage(imageUrl); 
Verwandte Themen