Javascript API cache query non url ?

WRInaute accro
Bonjour

Sous Javascript, c'est possible de mettre un objet en cache de cette manière :

array_param est un objet du type : keys / values.

fileRequest n'est pas une url.

Cà ne marche pas car l'API cache impose que la requête commence par http ou https.

Que faire ?

JavaScript:
    return new Promise(function(resolve, reject) {
      caches.open(cacheName).then(function(CACHE) {
             CACHE.put(fileRequest, array_param).then(function(result) {
                    // Traitement de result...
            }, {
                reject( .... );   // open
           })
     }, {
         reject(... );    // put
    })
   }, {
       reject(...);    // Promise
  });
 
WRInaute passionné
L'API CacheStorage ne permet que les URLs, donc utiliser l'API WebStorage avec la méthode localStorage.
 
WRInaute accro
Bonjour rick38

Merci beaucoup de ton avis.

Cependant, l'API Web Storage peut-elle être utilisée dans un service worker ?

Merci beaucoup.
 
WRInaute accro
Rebonjour rick38

Il semblerait ( à partir d'un service worker ), qu'il n'y ait la possibilité que PostMessage et IndexedDB.

Je vais introspecter. ;)

Merci beaucoup.
 
WRInaute accro
Pardon

Voici un essai avec MessageChannel et PostMessage.

Le problème consiste à laisser l'initiative au ServiceWorker d'envoyer ses demandes READ/WRITE d'accès au cache, accès gérés en dehors du serviceworker.

Les fonctions du main thread sont censées être accessibles par le service worker.

Il suffirait de les dupliquer.

Voici le code :


JavaScript:
/*****************************************************************/
/*                            MAIN THREAD                            **/
/*****************************************************************/
const isJson=function(item) {
        item = typeof item !== "string" ? JSON.stringify(item) : item;
        try {
                item = JSON.parse(item);
        } catch (e) {
                return false;
        }
        if (typeof item === "object" && item !== null) {
                return true;
        }
        return false;
}
const Type=function(value) {
        if (typeof value === 'undefined') {
                return 'undefined';
        }
        if(value === null) {
                return 'null';
        }
        if(typeof value === 'object' &&
                !Array.isArray(value)) {
                return 'object';
        }
        if(isJson=(value) {
                return 'Json';
        }
        if( Array.isArray(value)) {
                return 'array';
        }
        if(isNaN(value) {
                return 'NaN';
        }
        if (typeof value === 'boolean') {
                return 'boolean';
        }
        if (typeof value === 'bigint') {
                return 'bigint';
        }
        if (typeof value === 'number') {
                return 'number';
        }
        if (typeof value === 'string' || value instanceof String) {
                return 'string';
        }
        if !isNaN(Date.parse(value)) {
                return 'date';
        }
        if (typeof value === 'symbol') {
                return 'symbol';
        }
        if (typeof value === 'function') {
                return 'function';
        }
        return 'object';
}
Storage.prototype.setObject = function(key, value) {
        var tmp_type = Type(value);
        var tmp_array = ['object', 'array', 'Json', 'symbol'];
        if(tmp_array.indexOf(tmp_type) !== -1) {
                return this.setItem(key, JSON.stringify(value));
        }
        if(tmp_type === 'function') {
                return false;
        }
        this.setItem(key, value);
}
Storage.prototype.getObject = function(key) {
        var value = this.getItem(key);
        var tmp_type = Type(value);
        var tmp_array = ['object', 'array', 'Json', 'symbol'];
        if(tmp_array.indexOf(tmp_type) !== -1) {
                return value && JSON.parse(value);
        }
        return value;
}
function wrapObjectMessage(str_cache, message, object_message) {
        var array_message = ['READY', 'OK', 'READ', 'WRITE'];
        if(array_message.indexOf(message) == -1) {
                return false;
        }
        return {'cache': str_cache, 'type': message, 'object_cache': object_message};
}
function resObjectMessage(message) {
        var object_message = JSON.parse(message);
        return [object_message.str_cache, object_message.type, object_message.object_cache];
}
/*****************************************************/
/**                  ALGORITHME DE CACHE                **/
/*****************************************************/
/**    1)    INITIALISATION    => READY                    **/
/*****************************************************/
/**    2) SERVICE WORKER    => ASK READ | WRITE CACHE    **/
/*****************************************************/
/**    3) MAIN THREAD        =>    SEND READ CACHE            **/
/*****************************************************/
function sendMessage(str_cache, type, object_message) {
        var message = wrapObjectMessage(str_cache, message, object_message);
        // This wraps the message posting/response in a promise, which will resolve if the response doesn't
        // contain an error, and reject with the error if it does. If you'd prefer, it's possible to call
        // controller.postMessage() and set up the onmessage handler independently of a promise, but this is
        // a convenient wrapper.
        return new Promise(function(resolve, reject) {
                var messageChannel = new MessageChannel();
                messageChannel.port1.onmessage = function(event) {
                        if (event.data.error) {
                                reject(event.data.error);
                        } else {
                                console.log(`Received a message from service Worker: ${event.data}`);
                                resolve(event.data);
                        }
                };
                // This sends the message data as well as transferring messageChannel.port2 to the service worker.
                // The service worker can then use the transferred port to reply via postMessage(), which
                // will in turn trigger the onmessage handler on messageChannel.port1.
                // See https://html.spec.whatwg.org/multipage/workers.html#dom-worker-postmessage
                navigator.serviceWorker.controller.postMessage(message, [messageChannel.port2]);
        });
}
/*********************************/
/**        MAIN THREAD LISTEN        **/
/**    SERVICE WORKER MESSAGES    **/
/*********************************/
window.addEventListener('message', function(event) {
        var log                = console.log.bind(console);
        var error            = console.error.bind(console);
        var myStorage        = window.localStorage;
        var array_message    = resObjectMessage(event.data);
        var str_cache        = array_message[0];
        var type            = array_message[1];
        var object_message    = null;
        if(['READY', 'OK', 'READ', 'WRITE'].indexOf(type) === -1) {
                console.log('return type = ' + type);
                return false;
        }
       
        switch (type) {
                case 'OK' :
                        break;
                case 'READ' :
                        /*********************/
                        /**    LECTURE CACHE    **/
                        /*********************/
                        object_message = myStorage.getObject(str_cache);
                        /*************************/
                        /**        ACKNOWLEDGE        **/
                        /**      SERVICE WORKER    **/
                        /*************************/
                        sendMessage(str_cache, type, object_message).then(log, error).catch(error);
                        break;
                case 'WRITE' :
                        /*********************/
                        /**    ECRITURE CACHE    **/
                        /*********************/
                        object_message = array_message[2];
                        myStorage.setObject(str_cache, object_message);
                        /*************************/
                        /**        ACKNOWLEDGE        **/
                        /**      SERVICE WORKER    **/
                        /*************************/
                        sendMessage(str_cache, type, 'OK').then(log, error).catch(error);
                        break;
                default :
                        break;
        }
});
if ('serviceWorker' in navigator) {
        // Set up a listener for messages posted from the service worker.
        // The service worker is set to post a message to all its clients once it's run its activation
        // handler and taken control of the page, so you should see this message event fire once.
        // You can force it to fire again by visiting this page in an Incognito window.
        navigator.serviceWorker.addEventListener('message', function(event) {
        }
        // Wait until the service worker is active.
        navigator.serviceWorker.register('service-worker.js').then(function() {
                return navigator.serviceWorker.ready;
        }).then(function() {
                }).catch(function(error) {
                        // Something went wrong during registration. The service-worker.js file
                        // might be unavailable or contain a syntax error.
                        console.log(error);
                });
} else {
        console.log('This browser does not support service workers.');
}
/*********************************************************************/
/*                            SERVICE WORKER                            **/
/*********************************************************************/
/*************************************/
/**        service-worker.js LISTEN    **/
/**        MAIN THREAD  MESSAGES        **/
/*************************************/
var PORT = null;
self.addEventListener('message', function(event) {
        PORT = event.ports[0];
        console.log(`Received a message from main thread: ${event.data}`);
        var log                = console.log.bind(console);
        var error            = console.error.bind(console);
        var array_message    = resObjectMessage(event.data);
        var str_cache        = array_message[0];
        var type            = array_message[1];
        var object_message    = null;
        if(['READY', 'OK', 'READ', 'WRITE'].indexOf(type) === -1) {
                console.log('return type = ' + type);
                return false;
        }
       
        switch (type) {
                case 'READY' :
                        break;
                case 'READ' :
                        object_message    = array_message[2];
                        break;
                case 'WRITE' :
                        /*********************/
                        /**    ECRITURE CACHE    **/
                        /*********************/
                        object_message = array_message[2];
                        if(object_message !== 'OK') {
                                console.log(`Write message went wrong : ${event.data}`);
                        }
                        break;
                default :
                        break;
        }
});
/*****************************************/
/**                  EXAMPLES                **/
/**        ALL ASK FOR READ / WRITE CACHE    **/
/*****************************************/
/*****************/
/**        WRITE    **/
/*****************/
var message = wrapObjectMessage(str_cache, 'WRITE', object_to_cache);
PORT.postMessage(message);
/*****************/
/**        READ    **/
/*****************/
var message = wrapObjectMessage(str_cache, 'READ', null);
var message_object = PORT.postMessage(message);
var array_message = resObjectMessage(message_object);
var object_cached = array_message[2];
/*********************************************************************/
 
WRInaute accro
Bonjour

Voici l'algorithme, tel que je me le représente.

Peut-être faudrait-il associer un identifiant à chaque message.

Code:
            /*************************/
            /**        MAIN THREAD  **/----------------------------------------
            /*************************/                    |                  |
                |        |            |                    |                  |
              -----      |          -----                  |                  |
              | 1 |      |          | 3 |                  |                  |
              -----      |          -----                 /|\                 \|/
                |        |            |                    |                  |
                |        |            |                    |                  |
            ---------    |    -----------------            |                  |
            | READY |    |    |       READ    |            |                  |
            ---------    |    |    str_cache  |            |                  |
                |        |    |  obj_message  |            |                  |
                |        |    -----------------            |                  |
                |        |            |                    |                  |
               \|/       /|\         \|/                   |                  |
                |        |            |            -----------------    -------------
                |   -------------     |            |      WRITE    |    |      OK   |
                |   |     READ   |    |            |    str_cache  |    | str_cache |
                |   | str_cache  |    |            |  obj_message  |    -------------
                |   -------------     |            -----------------          |
                |        |            |                    |                  |
                |      -----          |                  -----               \|/
                |      | 2 |          |                  | 4 |                |
                |      -----          |                  -----              -----
                |        |            |                    |                | 5 |
                |        |            |                   /|\               -----
            /*************************/                    |                  |
            /**      SERVICE WORKER **/------------------------<---------------
            /*************************/


|/code]
 
Dernière édition:
WRInaute accro
Le problème persiste.

Impossible de conserver les valeurs de port1 et port2 entre chaque séquences WRITE ou bien READ.

L'initiative de l'ouverture d'une connexion MessageChannel, vient toujours du main thread, jamais du service worker.

Pourrait-on imaginer un système client-serveur, avec serveur dans le service worker, et client dans le main thread ou le service worker, avec connexion possible des clients vers le serveur, de manière à rendre possible les échanges WRITE, et READ ?

Ce concept ( à comparer avec une connexion HTTP, nécessiterait théoriquement un port serveur prévisible, sinon constant.

Théoriquement, une connexion MessageChannel, ne s'arrête qu'avec le close().

Comment savoir à l'avance le port serveur, tout en disposant d'un port client correct ?

Comment se connecter en MessageChannel, à un simili serveur ?

Si le problème est simplement la synchronisation entre initialisation WRITE ( ou READ ), et réponse WRITE ( ou READ ), comment savoir à quel moment débuter la connexion du main thread vers le service worker ?

Merci beaucoup de votre aide.

Amicalement.
 
WRInaute accro
Rebond

Je joins les ports port1 et port2 de MessageChannel aux postMessage, mais je ne sais pas quel serait le séquencement des messages entre le main thread ( page HTML : window ), et le ServiceWorker( navigator.serviceWorker.controller ).

Voici le code :

JavaScript:
/*****************************************************************/
/*                            MAIN THREAD                            **/
/*****************************************************************/
const isJson=function(item) {
        item = typeof item !== "string" ? JSON.stringify(item) : item;
        try {
                item = JSON.parse(item);
        } catch (e) {
                return false;
        }
        if (typeof item === "object" && item !== null) {
                return true;
        }
        return false;
}
const Type=function(value) {
        if (typeof value === 'undefined') {
                return 'undefined';
        }
        if(value === null) {
                return 'null';
        }
        if(typeof value === 'object' &&
                !Array.isArray(value)) {
                return 'object';
        }
        if(isJson=(value) {
                return 'Json';
        }
                if( Array.isArray(value)) {
                        return 'array';
                }
                if(isNaN(value) {
                        return 'NaN';
                }
                        if (typeof value === 'boolean') {
                                return 'boolean';
                        }
                        if (typeof value === 'bigint') {
                                return 'bigint';
                        }
                        if (typeof value === 'number') {
                                return 'number';
                        }
                        if (typeof value === 'string' || value instanceof String) {
                                return 'string';
                        }
                        if !isNaN(Date.parse(value)) {
                                return 'date';
                        }
                        if (typeof value === 'symbol') {
                                return 'symbol';
                        }
                        if (typeof value === 'function') {
                                return 'function';
                        }
                        return 'object';
                }
Storage.prototype.setObject = function(key, value) {
        var tmp_type = Type(value);
        var tmp_array = ['object', 'array', 'Json', 'symbol'];
        if(tmp_array.indexOf(tmp_type) !== -1) {
                try {
                        this.setItem(key, JSON.stringify(value));
                } catch (e) {
                        return 'FALSE';
                }
                return 'TRUE';
        }
        if(tmp_type === 'function') {
                return 'FALSE';
        }
        try {
                this.setItem(key, value);
        } catch (e) {
                return 'FALSE';
        }
        return 'TRUE';
}
Storage.prototype.getObject = function(key) {
        var value = this.getItem(key);
        var tmp_type = Type(value);
        var tmp_array = ['object', 'array', 'Json', 'symbol'];
        if(tmp_array.indexOf(tmp_type) !== -1) {
                try {
                        result = value && JSON.parse(value);
                } catch (e) {
                        return 'FALSE';
                }
                return result;
        }
        return value;
}
const wrapObjectMessage=function(ports, str_cache, message, object_message) {
        var array_message = ['READY', 'OK', 'READ', 'WRITE'];
        if(array_message.indexOf(message) == -1) {
                return false;
        }
        return JSON.stringify({'ports': ports, 'cache': str_cache, 'type': message, 'object_cache': object_message});
}
const resObjectMessage=function(message) {
        JSON.parse(message);
        return [object_message.ports, object_message.str_cache, object_message.type, object_message.object_cache];
}
/*****************************************************/
/**                  ALGORITHME DE CACHE                **/
/*****************************************************/
/**    1)    INITIALISATION    => READY                    **/
/*****************************************************/
/**    2) SERVICE WORKER    => ASK READ | WRITE CACHE    **/
/*****************************************************/
/**    3) MAIN THREAD        =>    SEND READ CACHE            **/
/*****************************************************/
const manageMessageFromWorker=function(message_object) {
        var log                = console.log.bind(console);
        var error            = console.error.bind(console);
        var    ports            = message_object.ports
        var std_cache        = message_object.str_cache;
        var type            = message_object.type;
        var object_message    = message_object.object_cache;
        if(['READY', 'OK', 'READ', 'WRITE'].indexOf(type) === -1) {
                console.log('return type = ' + type);
                return false;
        }
        /*****************************/
        /**    ENVOI => SERVICE WORKER    **/
        /*****************************/
        var    PORT1            = ports.port1;
        /*********************************/
        /**    RECEPTION <= SERVICE WORKER    **/
        /*********************************/
        var    PORT2            = ports.port2;
        var myStorage        = window.localStorage;
        var    message            = null;
        var response        = null;
        switch (type) {
                case 'OK' :
                case 'READY' :
              
                        return true;
                        break;
                case 'READ' :
                        /*********************/
                        /**    LECTURE CACHE    **/
                        /*********************/
                        object_message = myStorage.getObject(str_cache);
                        /*************************/
                        /**    RETOUR DE L'OBJET    **/
                        /**    AU SERVICE WORKER.    **/
                        /*************************/
                        message    = wrapObjectMessage(ports, str_cache, type, object_message);
                        try {
                                PORT1.postMessage(message);
                        } catch (e) {
                                return false;
                        }
                        return true;
                        break;
                case 'WRITE' :
                        /*********************/
                        /**    ECRITURE CACHE    **/
                        /*********************/
                        if((response = myStorage.setObject(str_cache, object_message)) === 'FALSE') {
                                return false;
                        }
                        /*************************/
                        /**        ACKNOWLEDGE        **/
                        /**      SERVICE WORKER    **/
                        /*************************/
                        message = wrapObjectMessage(ports, str_cache, type, response);
                        try {
                                PORT1.postMessage(message);
                        } catch (e) {
                                return false;
                        }
                        return true;
                        break;
                default :
                        break;
        }
        return false;
});
const initialization=function() {
        /*************************/
        /**        INITALIZE        **/
        /**      SERVICE WORKER    **/
        /*************************/
        var    message = null;
        var messageChannel = new MessageChannel();
        var ports = {'port1': [messageChannel.port1], 'port2': [messageChannel.port2]};
        try {
                message = wrapObjectMessage(ports, null, 'READY', null);
                navigator.serviceWorker.controller.postMessage(message);
        } catch (e) {
                return false;
        }
        return true;
}
window.addEventListener('message', function(event) {
        manageMessageFromWorker(event.data);
});
if ('serviceWorker' in navigator) {
        // Set up a listener for messages posted from the service worker.
        // The service worker is set to post a message to all its clients once it's run its activation
        // handler and taken control of the page, so you should see this message event fire once.
        // You can force it to fire again by visiting this page in an Incognito window.
        navigator.serviceWorker.addEventListener('message', function(event) {
        }
                // Wait until the service worker is active.
                navigator.serviceWorker.register('service-worker.js').then(function() {
                        return navigator.serviceWorker.ready;
                }).then(function() {
                }).catch(function(error) {
                        // Something went wrong during registration. The service-worker.js file
                        // might be unavailable or contain a syntax error.
                        console.log(error);
                });
} else {
        console.log('This browser does not support service workers.');
}
 
WRInaute accro
Rebonjour

A propos des variables globales à l'intérieur d'un service worker :

Après quel cycle du SW la variable disparaît ?

Si je peux mettre les ports du MessageChannel en variable globale, ces ports seraient utilisables continûment durant les échanges avec la page thtml.

Merci beaucoup de vos réponses.

Respectueusement.
 
Discussions similaires
Haut