2017-02-15 11 views
1

Web上で多くの記事が説明されているように、Service Workerを使用してWebアプリケーションにPush WebAPIを実装しました。 これで、Webアプリケーションが閉じられている間(クロムタブが閉じられ、バックグラウンドでサービスワーカーが実行されている間)、それらを利用できるようにするためにIndexedDB内にいくつかのデータを保存する必要があります。 特に、(サーバーから)通知データを取得する場所から単純なURLを格納したいと思います。Push WebAPI + IndexedDB + ServiceWorker

ここ

が私のコードです:

self.addEventListener("push", (event) => { 
    console.log("[serviceWorker] Push message received", event); 

    notify({ event: "push" }); // This notifies the push service for handling the notification 

    var open = indexedDB.open("pushServiceWorkerDb", 1); 
    open.onsuccess =() => { 
     var db = open.result; 
     var tx = db.transaction("urls"); 
     var store = tx.objectStore("urls"); 
     var request = store.get("fetchNotificationDataUrl"); 

     request.onsuccess = (ev) => { 
      var fetchNotificationDataUrl = request.result; 
      console.log("[serviceWorker] Fetching notification data from ->", fetchNotificationDataUrl); 

      if (!(!fetchNotificationDataUrl || fetchNotificationDataUrl.length === 0 || !fetchNotificationDataUrl.trim().length === 0)) { 
       event.waitUntil(
        fetch(fetchNotificationDataUrl, { 
         credentials: "include" 
        }).then((response) => { 
         if (response.status !== 200) { 
          console.log("[serviceWorker] Looks like there was a problem. Status Code: " + response.status); 
          throw new Error(); 
         } 

         return response.json().then((data) => { 
          if (!data) { 
           console.error("[serviceWorker] The API returned no data. Showing default notification", data); 
           //throw new Error(); 
           showDefaultNotification({ url: "/" }); 
          } 

          var title = data.Title; 
          var message = data.Message; 
          var icon = data.Icon; 
          var tag = data.Tag; 
          var url = data.Url; 

          return self.registration.showNotification(title, { 
           body: message, 
           icon: icon, 
           tag: tag, 
           data: { 
            url: url 
           }, 
           requireInteraction: true 
          }); 
         }); 
        }).catch((err) => { 
         console.error("[serviceWorker] Unable to retrieve data", err); 

         var title = "An error occurred"; 
         var message = "We were unable to get the information for this push message"; 
         var icon = "/favicon.ico"; 
         var tag = "notification-error"; 
         return self.registration.showNotification(title, { 
          body: message, 
          icon: icon, 
          tag: tag, 
          data: { 
           url: "/" 
          }, 
          requireInteraction: true 
         }); 
        }) 
       ); 
      } else { 
       showDefaultNotification({ url: "/" }); 
      } 
     } 
    }; 
}); 

私は新しいプッシュイベントを受信したとき残念ながら、それは動作しません、この例外を示す:

キャッチされない例外:DOMException:上の「WaitUntilにより」を実行できませんでした。 'ExtendableEvent':イベントハンドラは既に終了しています。 IDBRequest.request.onsuccessで (https://192.168.0.102/pushServiceWorker.js:99:23

どのように私はこの問題を解決することができますか?事前

答えて

2

event.waitUntil()の最初の呼び出しは、イベントハンドラが最初に呼び出されたときに同期的に行われる必要があるで

感謝。その後、約束のチェーンをevent.waitUntil()に渡すことができ、その約束のチェーン内では、任意の数の非同期アクションを実行できます。

event.waitUntil()を呼び出す前に、現在のコードで非同期IndexedDBコールバックが呼び出されます。そのため、そのエラーが表示されます。

約束チェーン内にIndexedDB操作を含める最も簡単な方法は、idb-keyvalのようなラッパー・ライブラリーを使用することです。このラッパー・ライブラリーは、コールバック・ベースのIndexedDB APIを使用して、それを約束ベースのAPIに変換します。

あなたのコードは、次のようになります。私はself.importScripts( '/ libsに/ IDB-KEYVAL/DIST/IDB-KEYVAL-min.js')を使用しました興味のあるものについて

self.addEventListener('push', event => { 
    // Call event.waitUntil() immediately: 
    event.waitUntil(
    // You can chain together promises: 
    idbKeyval.get('fetchNotificationDataUrl') 
     .then(url => fetch(url)) 
     .then(response => response.json()) 
     .then(json => self.registration.showNotification(...) 
); 
}); 
+0

。サービスワーカーからidb-keyvalを使用する – Androidian