How can i return status inside the promise?

I started to learning promise with loopback and jsforce, and couldn't handle this problem; I couldn't return status var inside promise to cb() function. Basically i want to connect salesforce and get data via JSforce and write it to db via loopback. Then want to return created/updated/error records to client after remote mothed called.

I'm developing with Loopback via using Node.JS & Express.js I'm using JSforce library to connect salesforce

How can I fix that?

Here is my code:

module.exports = function(Contact) {
  var jsforce = require('jsforce');
  var async = require("async");
  var lr = require('lr.js');

  Contact.ImportContacts = function(cb) {
    // Salesforce Projects List
    var sf_projects = [];
    //Salesforce Conn String
    var conn = lr.SalesforceConn();
    conn.apex.get("/Contact/", function(err, res) {
      var status = {
        "Created": [],
        "Updated": [],
        "Error": ""
      };
      if (err) console.log(err);

      sf_projects = res;
      // Clear result
      status.Created.length = 0;
      status.Updated.length = 0;
      status.Error = "";

      if (sf_projects != undefined) {
        async.eachSeries(sf_projects, function(contact, callback) {
          Contact.findOrCreate({
              where: {
                co_SalesforceID: contact.Id
              }
            }, {
              co_Name: contact.FirstName,
              co_Surname: contact.LastName,
              co_Salutation: contact.Salutation,
              co_Title: contact.Title,
              co_Department: contact.Department,
              co_Email: contact.Email,
              co_PhonePersonal: contact.HomePhone,
              co_PhoneWork: contact.Phone,
              co_PhoneCell: contact.MobilePhone,
              co_Description: contact.Description,
              co_SalesforceID: contact.Id
            },
            function(err, cntct, created) {
              if (err) console.log(err);
              if (created) {
                status.Created.push(cntct.id);
                console.log("Contact created. SalesForeID: " +
                  cntct.co_SalesforceID +
                  " ContactName: " +
                  lr.isDefined(cntct.co_Salutation) + " " +
                  lr.isDefined(cntct.co_Name) + " " +
                  lr.isDefined(cntct.co_Surname));
              } else {
                Contact.replaceById(cntct.id, {
                    co_Name: contact.FirstName,
                    co_Surname: contact.LastName,
                    co_Salutation: contact.Salutation,
                    co_Title: contact.Title,
                    co_Department: contact.Department,
                    co_Email: contact.Email,
                    co_PhonePersonal: contact.HomePhone,
                    co_PhoneWork: contact.Phone,
                    co_PhoneCell: contact.MobilePhone,
                    co_Description: contact.Description,
                    co_SalesforceID: contact.Id
                  },
                  false,
                  function(err, obj) {
                    if (err) console.log(err);
                    status.Updated.push(obj.id);
                    console.log("Contact updated. SalesForeID: " +
                      obj.co_SalesforceID + " ContactName: " +
                      lr.isDefined(obj.co_Salutation) + " " +
                      lr.isDefined(obj.co_Name) + " " +
                      lr.isDefined(obj.co_Surname));
                  });
              }
            });
          callback(err);
        }, function(err) {
          if (err) console.error(err);
        });
      } else {
        console.log("Salesforce Connection Error!");
        status.Error = "Salesforce Connection Error";
      }
      return Promise.resolve(status);
    }).then(function(end) {
      cb(null, end);

    }).catch(function(err) {
      if (err) console.log(err);
    });
  };
  Contact.remoteMethod(
    'ImportContacts', {
      returns: {
        arg: 'result',
        type: 'string'
      },
      http: {
        path: '/importContacts',
        verb: 'get'
      }
    }
  );
};

Answers:

Answer

It's not entirely clear what are asking about, and you don't include your solve() function which may be important here, so I can only give you some general tips.

You have something like this:

}).then(function(end) {
  cb(null, end);
}).catch(function(err) {
  if (err) console.log(err);
});

The first part (then) suggests that the cb() callback takes the error as the first argument and a value as the second argument, following the usual convention of Node callbacks.

But then in the second part (catch) you don't call the callback with the error. Also, the if (err) is redundant since in the catch handler there will always be an error, unless the solve() function returns a rejected promise with false or null specified as the rejection reason - and even then, whatever the rejection reason is, the callback should always be called in the case of error:

}).then(function(end) {
  cb(null, end);
}).catch(function(err) {
  console.log(err);
  cb(err);
});

That way you will not get a situation where the callback is never called and waits forever. When you mix promises with traditional callbacks you have to keep few things in mind:

Any function that gets a callback as an argument should make sure that this callback is called and that it is called exactly once. This is your responsibility as the function author to ensure that. In the case of error you should run:

callback(error);

and in the case of success you should call:

callback(null, data);

That way, the callback can know when the operation is finished and whether it finished with a success or failure by testing its first argument:

function (err, data) {
  if (err) {
    console.log('Error:', err);
  } else {
    console.log('Success:', data);
  }
}

The entire invocation of a function taking callback is usually:

functionTakingCallback('some', 'arguments', function (err, data) {
  if (err) {
    console.log('Error:', err);
  } else {
    console.log('Success:', data);
  }
});

On the other hand if the function returns a promise, you use it like this:

functionReturningPromise('some', 'arguments')
.then(function (data) {
  console.log('Success:', data);
})
.catch(function (err) {
  console.log('Error:', err);
});

No need for testing err in this case.

Callbacks should always be called exactly once. Promises should always be either resolved or rejected eventually. The usage is different and the responsibility of both the caller and the callee is different. When you mix those two styles - functions that take traditional Node-style callbacks and functions that return promises - then you have to be careful with those differences.

You can sometimes convert functions that take callbacks to functions that return promises using libraries like Bluebird and its promisify() and promisifyAll() to have consistent API for all your async functions in your entire code base. See:

You can see some other answers where I explain the difference between callbacks and promises and how to use them together in more detail, which may be helpful to you in this case:

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.