Combining two promises

I'm really new to JavaScript and promises, and to be honest, I don't quite understand how promises work, so I need help.

I am using Google Cloud Messaging to send notifications from my site to my users. When users receive a notification and click on it, it opens the URL stored in IndexedDB.

importScripts('IndexDBWrapper.js');
var KEY_VALUE_STORE_NAME = 'key-value-store', idb;

function getIdb() {
  if (!idb) {
    idb = new IndexDBWrapper(KEY_VALUE_STORE_NAME, 1, function (db) {
      db.createObjectStore(KEY_VALUE_STORE_NAME);
    });
  }
  return idb;
}

self.addEventListener('notificationclick', function (event) {
  console.log('On notification click: ', event);
  event.notification.close();
  event.waitUntil(getIdb().get(KEY_VALUE_STORE_NAME, event.notification.tag).then(function (url) {
    var redirectUrl = '/';
    if (url) redirectUrl = url;
      return clients.openWindow(redirectUrl);
  }));
});

      

So in the above code, I know that getIdb () ... then () is a promise, but is event.waitUntly also a promise?

The problem with the above code is that it opens a Chrome instance every time a notification is clicked and I would prefer it to use the existing instance if available. The following does exactly that:

self.addEventListener('notificationclick', function(event) {  
  console.log('On notification click: ', event.notification.tag);  
  event.notification.close();
  event.waitUntil(
    clients.matchAll({  
      type: "window"  
    })
    .then(function(clientList) {  
      for (var i = 0; i < clientList.length; i++) {  
        var client = clientList[i];  
        if (client.url == '/' && 'focus' in client)  
          return client.focus();  
      }  
      if (clients.openWindow) {
        return clients.openWindow('/');  
      }
    })
  );
});

      

However, I now have two promises, getIdb and clients.matchAll, and I really don't know how to combine the two promises and two sets of code. Any help would be greatly appreciated. Thank!

For reference: IndexDBWrapper.js:

'use strict';

function promisifyRequest(obj) {
  return new Promise(function(resolve, reject) {
    function onsuccess(event) {
      resolve(obj.result);
      unlisten();
    }
    function onerror(event) {
      reject(obj.error);
      unlisten();
    }
    function unlisten() {
      obj.removeEventListener('complete', onsuccess);
      obj.removeEventListener('success', onsuccess);
      obj.removeEventListener('error', onerror);
      obj.removeEventListener('abort', onerror);
    }
    obj.addEventListener('complete', onsuccess);
    obj.addEventListener('success', onsuccess);
    obj.addEventListener('error', onerror);
    obj.addEventListener('abort', onerror);
  });
}

function IndexDBWrapper(name, version, upgradeCallback) {
  var request = indexedDB.open(name, version);
  this.ready = promisifyRequest(request);
  request.onupgradeneeded = function(event) {
    upgradeCallback(request.result, event.oldVersion);
  };
}

IndexDBWrapper.supported = 'indexedDB' in self;

var IndexDBWrapperProto = IndexDBWrapper.prototype;

IndexDBWrapperProto.transaction = function(stores, modeOrCallback, callback) {
  return this.ready.then(function(db) {
    var mode = 'readonly';

    if (modeOrCallback.apply) {
      callback = modeOrCallback;
    }
    else if (modeOrCallback) {
      mode = modeOrCallback;
    }

    var tx = db.transaction(stores, mode);
    var val = callback(tx, db);
    var promise = promisifyRequest(tx);
    var readPromise;

    if (!val) {
      return promise;
    }

    if (val[0] && 'result' in val[0]) {
      readPromise = Promise.all(val.map(promisifyRequest));
    }
    else {
      readPromise = promisifyRequest(val);
    }

    return promise.then(function() {
      return readPromise;
    });
  });
};

IndexDBWrapperProto.get = function(store, key) {
  return this.transaction(store, function(tx) {
    return tx.objectStore(store).get(key);
  });
};

IndexDBWrapperProto.put = function(store, key, value) {
  return this.transaction(store, 'readwrite', function(tx) {
    tx.objectStore(store).put(value, key);
  });
};

IndexDBWrapperProto.delete = function(store, key) {
  return this.transaction(store, 'readwrite', function(tx) {
    tx.objectStore(store).delete(key);
  });
};

      

+3


source to share


2 answers


event.waitUntil()

takes over the promise - this allows the browser to keep your worker running until you finish what you want (i.e. until the promise you made is resolved event.waitUntil()

).

As the other answer suggests, you can use Promise.all()

internally event.waitUntil

. Promise.all()

takes an array of promises and returns a promise, so you can call it then

. Your processing function will receive an array of promises results when all the promises you provided Promise.all

have resolved. Then your code will look something like this (I haven't actually tested this, but it should be close):



self.addEventListener('notificationclick', function (event) {
  event.notification.close();
  event.waitUntil(Promise.all([
      getIdb().get(KEY_VALUE_STORE_NAME, event.notification.tag),
      clients.matchAll({ type: "window" })
    ]).then(function (resultArray) {
    var url = resultArray[0] || "/";
    var clientList = resultArray[1];
    for (var i = 0; i < clientList.length; i++) {
      var client = clientList[i];
      if (client.url == '/' && 'focus' in client)
        return client.focus();
    }
    if (clients.openWindow) {
      return clients.openWindow(url);
    }
  }));
});

      

+8


source


One way to work with multiple promises is with Promise.all

Promise.all([promise0, promise1, promise2]).then(function(valArray) {
    // valArray[0] is result of promise0
    // valArray[1] is result of promise1
    // valArray[2] is result of promise2
});

      



read about prom.all - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

+2


source







All Articles