2

In the code below, I am calling Pouch.sync(), to which I chain deleteLocal(). Pouch.sync() executes localDb.sync(), which does not return a promise, but I can attach a .on() event handler to handle errors.

I've tried playing around with $q.when and $q.reject, but I can't seem to prevent deleteLocal() from firing if the sync fails, and onError() never executes (either as an error callback or in the catch statement).

// Controller
function _onSyncClick() {
    return Pouch.sync()
        .then(deleteLocal, onError); // I do not want deleteLocal() to execute if Pouch.sync() fails
        .catch(onError); 
}


// Pouch service
function sync() {
    return 
        localDb.sync(remoteDb) 
            .on('error', function (err) {
                return $q.reject('Sync error.');
            });
}
devthorne
  • 197
  • 13

2 Answers2

0

.synch() uses a callback API, you can use $q.when and $q.reject to promisify it.

return localDB.sync(remoteDB).on('complete', function () {
   return $q.when("done!");
}).on('error', function (err) {
   return $q.reject(err);
});

Also, when chaining promises, you need to make sure you either throw an error or return a rejected promise, otherwise you will trigger the resolve/success handler.

so either .on('error', errorHandler) didn't ran as you though it would or Pouch.sync() didn't invoke your function.

svarog
  • 9,477
  • 4
  • 61
  • 77
  • Thank you. I did return `$q.reject()` in my error handler, but the chained function still executed. Using breakpoints, I confirmed that the error handler was indeed reached, but `deleteLocal()` still executed after the error. Why did `$q.reject()` not break the chain? – devthorne Aug 31 '16 at 18:46
  • i've accidentally used `.when` a second time, i've edited my answer – svarog Aug 31 '16 at 18:47
  • `but deleteLocal() still executed after the error.`, my guess is that the function was invoked by the `localDB.sync`. you can't run both success and reject handlers of a promise – svarog Aug 31 '16 at 18:52
0

First your then() shouldn't call deleteLocal with onError.

Next, based on the Angular documentation: If you "catch" an error via a promise error callback and you want to forward the error to the promise derived from the current promise, you have to "rethrow" the error by returning a rejection constructed via $q.reject

So you are treating a callback event as a Promise and maybe that's why is not trowing a reject.

The properly way I think is Promisify the callback events from sync() using the $q constructor.

// Controller
function _onSyncClick() {
  return Pouch.sync().then(deleteLocal).catch(onError);
}

// Pouch Service, method sync
function sync() {
  return $q(function (resolve, reject) {
    localDb.sync(remoteDb, {
      // options
    }).on('complete', function (info) {
      resolve(info);
    }).on('error', function (err) {
      reject(err);
    });
  });
}

Just to mention, the $q.when wraps an object that might be a value or a (3rd party) then-able promise into a $q promise, don't use it as a resolve, use it to wrap the PouchDB promises.

7ictor
  • 91
  • 6