2016-07-11 5 views
0

Mein Java-trainierter Verstand hat immer noch Schwierigkeiten, Javascript und die Verwendung von Versprechungen zu verstehen. Ich habe folgendes Setup:Wie man einen Wert, der von einem Versprechen für mehrere Funktionen zurückgegeben wird, richtig wieder verwendet

function foo() { 
    return Promise.resolve('foo'); 
} 

Funktion foo einen Wert zurückgibt, die in beiden Funktionen bar und baz benötigt wird:

function bar(foo) { 
    // process and use foo 
    return Promise.resolve('bar'); 
} 

function baz(foo,bar) { 
    return Promise.resolve(foo+bar); 
} 

Da baz() verwendet das Ergebnis von foo() und bar() Ich musste Kette sie wie dies:

foo() 
    .then((foo)=>{ 
     return bar(foo) 
     .then((bar)=>{ 
      return baz(foo,bar); 
     }) 
    }) 
    .then(console.log); 

Abhängig von der Anzahl der Funktionen, die baz folgen (die auch die Ergebnisse brauchen der vorherigen Funktionen) scheint dies ziemlich schnell hässlich zu werden.

Gibt es einen alternativen Weg, der einfacher zu lesen ist/einfacher?

+0

Vielleicht 'Promise.all'? – gcampbell

+2

Ein Versprechensobjekt ist unveränderlich. Sobald Sie es gelöst haben, bleibt es so lange, wie Sie die Browser-Registerkarte schließen. Sobald Sie mögen 'pr = foo(); pr.then (function (val) {doSomething (val)}) '' val' wird nicht ändern, wie oft Sie pr.then() getrennt aufrufen. Auf diese Weise können Sie den Rückgabewert des Versprechens in so vielen anderen Funktionen teilen, wie Sie möchten. – Redu

Antwort

0

Verwenden Sie einfach async/await:

;(async()=> { 
    const fooResult = await foo() 
    console.log(await baz(fooResult, await bar(fooResult))) 
})() 
+0

Wird dies bereits von Browsern oder node.js unterstützt? Ich dachte, dies ist noch in der Pipeline für ES7. – Rhayene

+0

@Rhayene Es befindet sich derzeit in der dritten Phase, wird jedoch bereits von Edge unterstützt. Sie können Babel verwenden, um Ihren Code zu kompilieren, damit er in allen Browsern funktioniert. –

+0

"ES7" wurde bereits als ES2016 veröffentlicht, es enthielt kein async/await, momentan strebt das TC nächstes Jahr an. Hoffentlich schaffen sie es. –

0

Es besteht keine Notwendigkeit für zukünftige Async-Syntax. Ich habe Angst, dass diese Funktion missbraucht wird.

const 
 
    foo =() => 
 
    Promise.resolve('foo') 
 

 
, bar = foo => 
 
    Promise.resolve('bar') 
 

 
, baz = (foo, bar) => 
 
    Promise.resolve(foo + bar) 
 

 
, delay = (ms, p) => 
 
    new Promise(res => 
 
    setTimeout(res, ms, p)) 
 

 
, randWait = p => 
 
    delay(Math.random() * 5000, p) 
 

 
, log = a => console.log(a) || a 
 

 
, str = a => 
 
    JSON.stringify(a, null, 2) 
 
    //Assuming bar needs to be called after foo has returned 
 
    //because of call signature in bar 
 

 
foo().then(f => bar(f).then(b => baz(f, b)).then(log)) 
 

 
//using Promise.all in a block so p doesn't become global 
 
//be carefull to ensure the call order lines up with 
 
//the next then call you can also pass your previous resolved 
 
// promises along in the array 
 
{ 
 
    let p; //temporary holder 
 
    Promise.all([p = foo(), p = p.then(bar)]).then(([f, b]) => 
 
    Promise.all([f, b, baz(f, b)])).then(log) 
 
} 
 

 
//To have named promises you can use an object instead 
 
//of an array if you use something like this 
 
const resolver = o => { 
 
    var keys = Object.keys(o) 
 
    return Promise.all(keys.map(a => o[a])).then((a, i) => 
 
    a.reduce((o, v, i) => 
 
     (o[keys[i]] = v, o), {})) 
 
} 
 

 
, fooPromise = randWait(foo()) 
 

 
, barPromise = fooPromise.then(bar) 
 

 
, bazPromise = resolver({ 
 
    b: barPromise, 
 
    f: fooPromise 
 
}).then(({ 
 
    f, b 
 
}) => baz(f, b)) 
 

 
, annoyingWait = randWait(bazPromise).then(a => 'did you really need to wait for me? ' + a) 
 

 
, all = resolver({ 
 
    annoyingWait, randWait, fooPromise, barPromise, bazPromise, nonPromise: 45, hiMom: delay(4000, 'hi') 
 
}) 
 

 
//Using Await takes a lot of the power away from promises 
 
//because, while it may not block the whole system, it will often 
 
//unneccesarily pause parts of the code. Promises can give you a 
 
//much more fine gain control over async events. 
 

 
, justFooBazAndBar = resolver({ 
 
    foo: fooPromise, 
 
    baz: bazPromise, 
 
    bar: barPromise 
 
}) 
 

 
all.then(str).then(log) 
 

 
justFooBazAndBar.then(log).then(o => 
 
    //merge the object to be available to to the next promise 
 
    //use object.assign because promises results should always 
 
    //be immutable. 
 
    Object.assign({}, o, { 
 
    altBar: bar(o.foo + '2', o.bar + '2') 
 
    })).then(str).then(log)

+0

Es tut mir leid, wenn mein Beispiel fehlte oder ich immer noch nicht verstehe (ich bin noch ein Anfänger hier :)): Wie benutze ich die Ergebnis von 'foo()' in 'bar (foo)' in Ihrem Promise.all Beispiel? – Rhayene