如何正确地重用承诺为多个函数返回的值

时间:2016-07-11 10:07:54

标签: javascript promise

我受过Java训练的头脑仍然难以理解Javascript和承诺的使用。我有以下设置:

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

函数foo返回函数bar和baz中所需的值:

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

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

由于baz()使用foo()bar()的结果,我必须将它们链接起来:

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

根据baz后面的函数数量(也需要前面函数的结果),这似乎很快变得丑陋。

是否有另一种方式,更容易阅读/更直接?

2 个答案:

答案 0 :(得分:0)

只需使用async / await:

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

答案 1 :(得分:0)

不需要将来的Async语法。我有点害怕这个功能会被滥用。



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)