2

I am creating a offline first blogging platform which utilises IndexedDB and service workers. The idea here is if the user is offline and trying to send a post - send it in the background. This project is for my dissertation, I have only been looking at promises for a week or so - apologies if it is a simple error!

From my action in react/redux, i'm sending the sync event through successfully.

Below is the code for my sync event handler

self.addEventListener('sync', function(event) {
  if (event.tag == 'send_post') {
    //const URL
    console.log('sync from SW - send post');
    //this should try again if promise is rejected
    event.waitUntil(
      openDatabase('Outbox').then( (db) => {
        return databaseGet('posts',db).then( (posts) => {
          return sendAllFromOutbox(posts)
        } )
      } )

    );
  }
});

Below is openDatabase - (IndexedDB)

    function openDatabase(name) {
      return new Promise(function(resolve, reject) {
        var version = 10;
        var request = indexedDB.open(name, version);
        var db;
        request.onupgradeneeded = function(e) {
          db = e.target.result;
          e.target.transaction.onerror = reject;
        };
        request.onsuccess = function(e) {
          db = e.target.result;
          console.log('OPENED DATABASE');
          resolve(db);
        };
        request.onerror = reject;
      });
    }

Below is databaseGet

function databaseGet(type,db) {
  return new Promise(function(resolve, reject) {
    var transaction = db.transaction([type], 'readonly');
    var store = transaction.objectStore(type);
    var request = store.getAll();
    request.onsuccess = function(e) {
      var result = e.target.result;
      resolve(result);
    };
    request.onerror = reject;
  });
}

And finally, below is sendAllFromOutbox

function sendAllFromOutbox(posts) {
  return fetch('https://stirapi.herokuapp.com/sendPost', {
    headers: {'Content-Type': 'application/json'},
    method: "POST",
    body: JSON.stringify(posts)
  })
  .then( (response) => {
    console.log('response from SW sendAllFromOutbox', response);
  } )
  .catch( (err) => {
    console.log('error from SW sendAllFromOutbox',err);
  } )
}

From my understanding, if sendAllFromOutbox fails/rejects - it should get called again. But it doesn't seem to be getting called - and therefore is not being sent in the background.

If you would like to check out my repo - it's here https://github.com/georgecook92/Stir.

Thank you!

George

George Cook
  • 306
  • 3
  • 12
  • 1
    This isn't your problem, just a general warning: be careful when mixing IDB and promises, they don't always play well together. See the example in https://crbug.com/457409. – dgrogan Aug 04 '16 at 23:30
  • Thank you! Could you explain this a little more? I thought the sendAllFromOutbox function would control whether the function should get called or not? This is just a fetch which takes data from a previous IDB call? Apologies if I misunderstand, new to promises! – George Cook Aug 06 '16 at 11:08
  • IDB and promises is much better than it used to be. See https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/ – JaffaTheCake Aug 08 '16 at 19:42

1 Answers1

1

It's down to the browser to decide when the failed sync event should be retried. Also, it won't retry infinitely, but you know it's the last attempt via syncEvent.lastChance (spec).

Looking at your code above, databaseGet expects (type,db), but you call it databaseGet('posts'), so that'll throw an error when you try and access properties of db, which is undefined. Chrome's devtools should show this, especially with "break on caught errors".

The idea here is if the user is offline and trying to send a post - send it in the background

It's best to use background sync regardless of the user's current state. Sure, navigator.onLine will tell you if the user is definitely offline, but if onLine is true the user still may not have a reliable connection.

JaffaTheCake
  • 13,895
  • 4
  • 51
  • 54
  • Thank you! I used your example online, and changed it to remove the global db and pass it through the chain. I must have copied an older version of the function, apologies! It still appears that there are no retries. The full code is available in my repo - https://github.com/georgecook92/Stir/blob/master/sw.js Thank you for the advice regarding using sync on all requests! Appreciate the response! – George Cook Aug 09 '16 at 13:56