2016-08-29 3 views
5

Ich habe Versprechen Objekte, die arbeiten müssen synchronisieren. Zum Beispiel sollte das zweite Versprechen nicht funktionieren, bevor das erste getan ist. Wenn der erste Ausschuss abgelehnt wird, muss er erneut ausgeführt werden.Wie synchronisiert man Promise-Objekte?

Ich habe ein paar Beispiele implementiert. Das funktioniert gut. getVal rufen, warten 2000 ms, Rückkehr, i ++, rufen Sie wieder getVal .....

getVal() { 
     return new Promise(function(resolve, reject) { 
     setTimeout(function(){ resolve(19) }, 2000); 
     }); 

    } 

async promiseController(){ 

    for(var i =0;i<5;i++) 
     { 
     var _val = await this.getVal() 
     console.log(_val+'prom'); 
     } 
    } 

Aber ich brauche, um eine Reihe von Versprechen Objekte zu steuern. Was ich machen möchte ist, dass ich Daten habe und teile sie in 5 Teile. Nachdem der erste Teil bearbeitet wurde (zB: an den Server geschickt) will ich den zweiten Teil bearbeiten ansonsten muss ich den ersten Teil nochmal bearbeiten.

Dies ist der Prototyp-Implementierung I

getVal() { 
    return new Promise(function(resolve, reject) { 
    setTimeout(function(){ resolve(19) }, 2000); 
    }); 

} 

async promiseController(){ 
    var proms=[] 
    for(var i =0;i<5;i++) 
    { 
     proms.push(this.getVal()) 
    } 

for(var i =0;i<5;i++) 
    { 
    var _val = await proms[i] 
    console.log(_val+'prom'); 
    } 
} 
gemacht

Promises Objekte in diesem Code sequentiell arbeitet. Wie kann ich den Code unten beheben, so dass es als erstes Beispiel synchron arbeitet.

+1

Ich kann nicht sagen, ob Sie versuchen, eine ['Promise.all()'] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) zu machen (alle) oder wenn du deine Versprechen haben willst, mehr von einem Wasserfall zu machen. – zero298

+0

promise.all() funktioniert nicht für mich. Es lehnt die Linie nach einem Versprechen ab. In meiner Situation muss ich alle arbeiten, sonst ist es nutzlos. –

+0

Was wird erwartet, wenn der rekursive Aufruf, der das erste Versprechen zurückgibt, nicht aufgelöst wird? – guest271314

Antwort

3
async promiseController(){ 
    for(const value of array) { 
    console.log((await this.getVal(value))+'prom'); 
    } 
} 

Keine Notwendigkeit, die Dinge verkomplizieren. Rufen Sie einfach await innerhalb der Schleife und es wird warten, was Sie wollen.

Wie die andere Antwort rechtmäßig gesagt - ein Versprechen stellt einen Wert und keine Operation. Für Operationen werden reguläre Funktionen verwendet.

Wenn Sie Fehler ignorieren möchten, können Sie .catch(() => {}) auf das Versprechen. Wenn Sie bis zum Fehler wiederholen wollen - können Sie auf eine Funktion wiederholen Refactoring und verwenden, die:

const retry = fn => (...args) => fn(...args).catch(retry(fn)); 
+0

danke aber wie ich in der Frage erwähnt habe ich Array versprechen. Calling getVal funktioniert nicht für mich –

+0

Das macht keinen Unterschied, anstatt von 0 bis 4 zu iterieren die Werte. Ich habe das Beispiel aktualisiert, um zu zeigen, dass anstelle von 0..4 –

+0

Sie meinen (warten Sie auf diesen.getVal (Wert)) oder (erwarten Sie Wert) –

1

Wenn Ihr Ziel ist nicht „die nachfolgenden Versprechen auszuführen“ ist, bis das erste Versprechen löst, dann müssen Sie im Auge behalten, die bereits asynchrone Aktivität verspricht repräsentieren im Flug. Sobald das Versprechen besteht, ist es zu spät.

Sie müssen stattdessen die nachfolgenden Forecast Factory-Methoden nicht aufrufen, bis das erste Versprechen abgeschlossen ist. Ihr erstes Beispiel tut dies, indem Sie getVal() nicht aufrufen, bis das vorherige Versprechen abgeschlossen ist.

Damit Sie am Ende mit etwas wie:

delay(time) { 
    return new Promise(resolve => setTimeout(resolve, time)); 
} 

async promiseController() { 
    const factories = []; 
    for (let i = 0; i < 5; ++i) { 
     factories.push(() => this.getVal()); 
    } 

    for (const f of factories) { 
     // keep running this factory until it succeeds 
     let success = false; 
     while (!success) { 
      try { 
       const promise = f(); 
       const result = await f; 
       success = true; 
       console.log(`result = ${result}`); 
      } 
      catch (err) { 
       console.log("promise failed. retrying"); 
       await delay(100); 
      } 
     } 
    } 
} 
+0

dank zurückgibt. Sie sagen "Ihr erstes Beispiel tut dies, indem Sie getVal() nicht aufrufen, bis das vorherige Versprechen abgeschlossen ist." Was ist falsch mit 2. Beispiel. Was ist der Unterschied zwischen warten auf diese.getVal() und warten auf Bälle [i]. Beide haben ein Versprechen, nicht wahr? –

1

Sie Rekursion, benannte Funktion verwenden können, .then()

var arr = [Promise.resolve("a") 
 
      , Promise.resolve("b") 
 
      , Promise.resolve("c")]; 
 
var i = 0; 
 
var res = []; 
 

 
function foo() { 
 
    // conditional resolved or rejected promise 
 
    var n = String(new Date().getTime()).slice(-1); 
 
    // if `n` < 5 reject `n` , else resolve `n` 
 
    var curr = n < 5; 
 
    return curr ? arr[i] : Promise.reject(["rejected", n]) 
 
} 
 

 
var p = (function repeat() { 
 
    var promise = foo(); 
 
    return promise 
 
    .then(function(data) { 
 
     console.log(data); 
 
     res.push(data); 
 
     ++i; 
 
     if (i < arr.length) return repeat() 
 
     // return `res` array when all promises complete 
 
     else return res 
 
    }) 
 
    .catch(function(err) { 
 
     console.log(err); 
 
     if (err[0] === "rejected") return repeat() 
 
    }) 
 
}()); 
 

 
p.then(function(complete) { 
 
    console.log("complete:", complete) 
 
});

1

Gut OK . Ich glaube aus Gründen der ordnungsgemäßen Funktionsprogrammierung sollte das async und await Ding vermieden werden. Ich glaube, Versprechungen sind sehr ausreichend. Wenn Sie jedoch weiterhin in C++ ish imperativem Stil codieren möchten, dann ist async und await für Sie.

Ich habe Versprechen Objekte, die arbeiten müssen synchronisieren. Zum Beispiel zweite Versprechen sollte nicht funktionieren, bevor zuerst getan wird. Wenn die erste die erste ablehnt, muss sie erneut ausgeführt werden.

Lassen Sie mich einen kurzen Überblick über den folgenden Code geben. Wir haben die async() Funktion, die eine Daten und einen Rückruf (Fehler erster Typ) nimmt. Zu Demonstrationszwecken wird versucht, den Callback mit Daten innerhalb von 2000ms aufzurufen, jedoch gibt es ein Timeout von 1000ms. So 50-50 wird es entweder den Rückruf mit Daten oder Fehler aufrufen.

Also brauchen wir es tatsächlich, um uns ein Versprechen zurückzugeben, also verifiziere ich es mit Hilfe von promisify() und es dauert async() Funktion und gibt mir die asyncPro() Funktion zurück. Das ist in der Tat dasselbe wie async(), gibt aber stattdessen ein Versprechen zurück. Wir erwarten daher, dass wir unseren Rückruf unter then durchführen.

Dann kommt tryNTimes(data,asyncFun,n = 5) Funktion, die Daten, eine promisified Async-Funktion und eine ganze Zahl, die die Anzahl der Versuche versucht, bevor es ablehnt. Es ist standardmäßig try count ist 5, aber Sie können es auf einen beliebigen Wert setzen, indem Sie das dritte Argument übergeben.

Für den letzten Teil haben wir die flowControl(), die unsere Versprechen perfekt mit Hilfe von Array.prototype.reduce() verkettet.

So jetzt haben wir alle unsere Versprechen nacheinander verkettet und keiner wird versagen, bevor es 5 mal versucht.

function promisify(fun){ 
 
    return (data) => new Promise((resolve,reject) => fun(data, (err,res) => err ? reject(err) : resolve(res))); 
 
} 
 

 
function async(data, callback){ 
 
    var dur = Math.floor(Math.random()*2000); 
 
    setTimeout(_ => callback(false,data),dur);   // may resolve before timeout 
 
    setTimeout(_ => callback("error at " + data),1000); // timeout at 1 sec 
 
} 
 

 
function tryNTimes(data,asyncFun,n = 5){ 
 
    return new Promise((resolve,reject) => { n === 0 && reject("try out fail at 5 tries: " + data); 
 
              asyncFun(data).then(v => resolve("resolved at countdown " + n + ": " + v)) 
 
                 .catch(e => resolve(tryNTimes(data,asyncFun,--n))); 
 
             }); 
 
} 
 

 
function flowControl(d,f,tc){ 
 
    return d.reduce((prom,chunk) => prom.then(v => { console.log(v); 
 
                return tryNTimes(chunk,f,tc); 
 
               }),Promise.resolve("initial dummy promise")); 
 
} 
 

 
var data = ["chunk_1", "chunk_2", "chunk_3", "chunk_4", "chunk_5"], 
 
asyncPro = promisify(async);       // now our async function returns a promise 
 

 
flowControl(data,asyncPro).then(v => console.log(v)) 
 
          .catch(e => console.log(e));

Wenn Sie die sehen möchten "5 mal versuchen" Fehler häufiger den Timeout-Wert in async() Funktion senken bitte.

+0

danke für dieses detaillierte und erklärende schöne Beispiel. Ich habe keinen Schritt verstanden. Promise hat eine Executer-Funktion und diese Funktion wird sofort ausgeführt (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) Du hast diese Funktion async richtig gemacht? Wie kann die Funktion async dazu führen, dass diese Funktion nicht sofort aufgerufen wird? –

+0

@Burak Karasoy Nicht die Async. Ja, wenn Sie ein Promise-Objekt generieren, wird eine Executer-Funktion ausgeführt und in unserem Beispiel befindet sich der Executer in der 'promisfy'-Funktion.' (Auflösen, ablehnen) => fun (data, (err, res) => err? ablehnen (err): auflösen (res)) 'Es wird synchron ausgeführt und gibt Ihnen ein Versprechen-Objekt zurück, das auf unsere 'asynchrone' Funktionsauflösung oder -unterdrückung wartet. Wenn Sie 'asyncPro = promisify (async) schauen;' Anweisung macht unsere 'async'-Funktion zum' fun'-Argument im 'promisfy' und wir stellen die" resolve "- und" reject "-Rückrufe unserer Executer für die 'async'-Funktion – Redu

+0

bereit promisify() gibt kein Versprechen zurück, sondern gibt eine Funktion zurück, die ein Versprechen zurückgibt. Deshalb wird das Versprechen nicht sofort ausgelöst, sondern nachdem die Methode aufgerufen wurde, richtig? und muss der Name der Methode in dieser Situation async sein? Oder nannten Sie es async, nur weil es setTimeout (..) hat, können Sie es nicht _asyncFunc anstelle von async nennen –

Verwandte Themen