2

I am trying to chain data from an API request together and would like to gather promises from two of the blocks into a third then.

The pattern is as follows:

sql.connect(config.properties).then(pool => {
  return pool.request()
    .execute('stored_proc')
    .then(response => { res.send(response) })
    .catch(err => { res.send(err) })
    .then((response, err) => { someFunction(response, err) }) // bundle here
    .finally(() => sql.close())
})

How can I pass response and err into the second then block to pass into a function?

Matthew
  • 1,461
  • 3
  • 23
  • 49
  • 1
    am not sure why `err` is in your `then`. to return the response, do something like: `.then((response, err) => { someFunction(response, err); return response; }).then(response => { DoSomething(response); }` – Rafael Herscovici Jul 11 '19 at 20:37
  • Can you use `async / await`, if you not using a very old version of node, then the answer here would be yes. One advantage of `async/await` here is that you have the benefits of closures, if not you will have to pass everything down the promise chain. – Keith Jul 11 '19 at 20:38
  • 1
    @Santi In theory the execute could succeed, but the res.send could fail, so you could have a response and error. – Keith Jul 11 '19 at 20:40
  • 1
    @Keith Understood, thank you. – Santi Jul 11 '19 at 20:41
  • With `someFunction` id like to pass either `response` or `err` to a log... – Matthew Jul 11 '19 at 20:42
  • I'm not sure if `res.send` is async, but my guess would be yes. I can't find its full definition in the `Express` docs. – Matthew Jul 11 '19 at 20:43
  • @Keith What would the `async/await` pattern look like? – Matthew Jul 11 '19 at 20:44
  • @Matthew I'll knock up a quick snippet.. – Keith Jul 11 '19 at 20:45

2 Answers2

3

I would recommend calling the someFunction in the two locations where those values are actually available:

return pool.request()
.execute('stored_proc')
.then(response => {
  res.send(response);
  someFunction(response, null);
})
.catch(err => {
  res.send(err);
  someFunction(null, err);
})
.finally(() => sql.close())

However, given the difference between .then(…, …) and .then(…).catch(…) I would in fact recommend

return pool.request()
.execute('stored_proc')
.then(response => {
  res.send(response);
  someFunction(response, null);
}, err => {
  res.send(err);
  someFunction(null, err);
})
.finally(() => sql.close())

Now if you really want to pass the values into a following then callback, you can simply return them. Use an array to transport two values:

return pool.request()
.execute('stored_proc')
.then(response => {
  res.send(response);
  return [response, null];
}, err => {
  res.send(err);
  return [null, err];
})
.then(([response, err]) => {
  someFunction(response, err);
})
.finally(() => sql.close())
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

Using async/await, that is now included with Node.js.

You could do something like ->

sql.connect(config.properties).then(async pool => {
  try {
    let response = null; //let's set to null, in case it doesn't even get that far
    try {
      response = await pool.request().execute('stored_proc');
      res.send(response);
      someFunction(response, null);
    } catch (err) {
      res.send(err);
      someFunction(response, err);
    }
  } finally {
    sql.close();
  }
})

The advantage here is that we can keep a closure on the response, I've set it to null also, because in theory it might not even get as far as getting a response.

What make async/await do nice, it that you can go back to thinking in a sync way, but the code still runs async, so all normal try / catch / finally work as you would expect, for loops work as you would imagine etc. Just be careful of Array.forEach, and thing's that take callbacks, as that might not work the way you expect.

Keith
  • 22,005
  • 2
  • 27
  • 44