0

My Java trained mind still struggles to understand Javascript and the use of promises. I have the following setup:

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

Function foo returns a value that is needed in both functions bar and baz:

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

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

Since baz() uses the result of foo() and bar() I had to chain them like this:

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

Depending on the number of functions that follow baz (that also need the results of the previous functions) this seems to get ugly pretty quickly.

Is there an alternative way, that is easier to read/ more straight forward?

Rhayene
  • 805
  • 9
  • 20
  • Maybe `Promise.all`? – gcampbell Jul 11 '16 at 10:11
  • 2
    A promise object is immutable. So you once it gets resolved it stays so as long as you close the browser tab. Once you do like `pr = foo(); pr.then(function(val) {doSomething(val)})` `val` won't change how many separate times you call pr.then(). So this way you can share the return value of the promise in as many other functions as you may like. – Redu Jul 11 '16 at 13:12

2 Answers2

0

Just use async / await:

;(async ()=> {
  const fooResult = await foo()
  console.log(await baz(fooResult, await bar(fooResult)))
})()
Michał Perłakowski
  • 88,409
  • 26
  • 156
  • 177
0

There is no need for future Async syntax. I am sort of scared that feature will get abused.

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)
James Wakefield
  • 526
  • 3
  • 11
  • I'm sorry if my example was lacking or I still don't understand (I'm still a beginner here :)): how do I use the result of `foo()` in `bar(foo)` in your Promise.all example? – Rhayene Jul 11 '16 at 14:08