Chaining Promises and Passing Parameters between Them

86 Views Asked by At

I'm new to Node/Express and am trying to use Promises to executive successive API calls to Apple's CloudKit JS API.

I'm unclear on how to put the functions in sequence and pass their respective return values from one function to the next.

Here's what I have so far:

var CloudKit = require('./setup')

//----
var fetchUserRecord = function(emailConfirmationCode){
  var query = { ... }

  // Execute the query
  CloudKit.publicDB.performQuery(query).then(function (response) {
    if(response.hasErrors) {
      return Promise.reject(response.errors[0])
    }else if(response.records.length == 0){
      return Promise.reject('Email activation code not found.')
    }else{
      return Promise.resolve(response.records[0])
    }
  })
}

//-----
var saveRecord = function(record){
  // Update the record (recordChangeTag required to update)
  var updatedRecord = { ... }

  CloudKit.publicDB.saveRecords(updatedRecord).then(function(response) {
    if(response.hasErrors) {
      Promise.reject(response.errors[0])
    }else{
      Promise.resolve()
    }
  })
}

//----- Start the Promise Chain Here -----
exports.startActivation = function(emailConfirmationCode){

  CloudKit.container.setUpAuth() //<-- This returns a promise
  .then(fetchUserRecord) //<-- This is the 1st function above
  .then(saveRecord(record)) //<-- This is the 2nd function above
    Promise.resolve('Success!')
  .catch(function(error){
    Promise.reject(error)
  })

}

I get an error near the end: .then(saveRecord(record)) and it says record isn't defined. I thought it would somehow get returned from the prior promise.

It seems like this should be simpler than I'm making it, but I'm rather confused. How do I get multiple Promises to chain together like this when each has different resolve/reject outcomes?

2

There are 2 best solutions below

2
On BEST ANSWER

There are few issues in the code.

First: you have to pass function to .then() but you actually passes result of function invocation:

.then(saveRecord(record))

Besides saveRecord(record) technically may return a function so it's possible to have such a statement valid it does not seem your case. So you need just

.then(saveRecord)

Another issue is returning nothing from inside saveRecord and fetchUserRecord function as well.

And finally you don't need to return wrappers Promise.resolve from inside .then: you may return just transformed data and it will be passed forward through chaining.

var CloudKit = require('./setup')

//----
var fetchUserRecord = function(emailConfirmationCode){
  var query = { ... }

  // Execute the query
  return CloudKit.publicDB.performQuery(query).then(function (response) {
    if(response.hasErrors) {
      return Promise.reject(response.errors[0]);
    }else if(response.records.length == 0){
      return Promise.reject('Email activation code not found.');
    }else{
      return response.records[0];
    }
  })
}

//-----
var saveRecord = function(record){
  // Update the record (recordChangeTag required to update)
  var updatedRecord = { ... }

  return CloudKit.publicDB.saveRecords(updatedRecord).then(function(response) {
    if(response.hasErrors) {
      return Promise.reject(response.errors[0]);
    }else{
      return Promise.resolve();
    }
  })
}

//----- Start the Promise Chain Here -----
exports.startActivation = function(emailConfirmationCode){

  return CloudKit.container.setUpAuth() //<-- This returns a promise
    .then(fetchUserRecord) //<-- This is the 1st function above
    .then(saveRecord) //<-- This is the 2nd function above
    .catch(function(error){});
}

Don't forget returning transformed data or new promise. Otherwise undefined will be returned to next chained functions.

3
On

Since @skyboyer helped me figure out what was going on, I'll mark their answer as the correct one.

I had to tweak things a little since I needed to pass the returned values to subsequent functions in my promise chain. Here's where I ended up:

exports.startActivation = function(emailConfirmationCode){
  return new Promise((resolve, reject) => {

    CloudKit.container.setUpAuth()
      .then(() => {
        return fetchUserRecord(emailConfirmationCode)
      })
      .then((record) => {
        resolve(saveRecord(record))
      }).catch(function(error){
        reject(error)
      })

  })
}