Travailleurs Web sans fichier Javascript séparé?


291

Pour autant que je sache, les travailleurs Web doivent être écrits dans un fichier JavaScript séparé et appelés comme ceci:

new Worker('longrunning.js')

J'utilise le compilateur de fermeture pour combiner et réduire tout mon code source JavaScript, et je préfère ne pas avoir mes employés dans des fichiers séparés pour la distribution. Y a-t-il un moyen de le faire?

new Worker(function() {
    //Long-running work here
});

Étant donné que les fonctions de première classe sont si cruciales pour JavaScript, pourquoi la méthode standard de travail en arrière-plan doit-elle charger un autre fichier JavaScript à partir du serveur Web?


7
C'est parce que garder un contexte d'exécution purement threadsafe est encore plus crucial que les fonctions de première classe :-)
Pointy

1
J'y travaille (ou plutôt pour minimiser le problème): DynWorker . Vous pouvez faire: var worker = new DynWorker(); worker.inject("foo", function(){...});...
Félix Saparelli


1
L'OP a supprimé la question «Enseignant à accepter la fonction au lieu du fichier source JavaScript». La réponse est republiée ici
Rob W

J'ai développé task.js pour rendre cela beaucoup plus facile à faire. La plupart du temps, vous essayez uniquement de décharger de petites tâches de verrouillage.
Chad Scira

Réponses:


225

http://www.html5rocks.com/en/tutorials/workers/basics/#toc-inlineworkers

Que faire si vous souhaitez créer votre script de travail à la volée ou créer une page autonome sans avoir à créer des fichiers de travail distincts? Avec Blob (), vous pouvez "inline" votre travailleur dans le même fichier HTML que votre logique principale en créant une poignée URL vers le code du travailleur sous forme de chaîne


Exemple complet de travailleur en ligne BLOB:

<!DOCTYPE html>
<script id="worker1" type="javascript/worker">
  // This script won't be parsed by JS engines because its type is javascript/worker.
  self.onmessage = function(e) {
    self.postMessage('msg from worker');
  };
  // Rest of your worker code goes here.
</script>
<script>
  var blob = new Blob([
    document.querySelector('#worker1').textContent
  ], { type: "text/javascript" })

  // Note: window.webkitURL.createObjectURL() in Chrome 10+.
  var worker = new Worker(window.URL.createObjectURL(blob));
  worker.onmessage = function(e) {
    console.log("Received: " + e.data);
  }
  worker.postMessage("hello"); // Start the worker.
</script>


La seule solution de Google Chrome, Firefox 10 le supportera, je ne sais pas pour les autres navigateurs
4esn0k

2
BlobBuiler est désormais obsolète . Utilisez plutôt Blob . Actuellement pris en charge dans les derniers Firefox / WebKit / Opera et IE10, voir les tableaux de compatibilité pour les anciens navigateurs.
Félix Saparelli

3
Le constructeur d'objets blob peut être pris en charge dans IE10, mais vous ne pouvez toujours pas transmettre javascript au travailleur Web via ce dernier (pas même dans IE11): connect.microsoft.com/IE/feedback/details/801810/… .
jayarjo

1
@albanx - quels tests? il y a déjà des milliards de pages de démonstration en ligne qui montrent que le filetage ne bloque pas le navigateur depuis des années.
vsync

2
@albanx - voudriez-vous au moins dire quel navigateur ésotérique utilisez-vous et qui se bloque? est-ce que cette démo vous pend? ie.microsoft.com/testdrive/Graphics/WorkerFountains/…
vsync

162

La solution html5rocks consistant à incorporer le code du travailleur Web en HTML est assez horrible.
Et un blob de JavaScript échappé en tant que chaîne n'est pas mieux, notamment parce qu'il complique le flux de travail (le compilateur de fermeture ne peut pas fonctionner sur les chaînes).

Personnellement, j'aime vraiment les méthodes toString, mais @ dan-man QUE regex!

Mon approche préférée:

// Build a worker from an anonymous function body
var blobURL = URL.createObjectURL( new Blob([ '(',

function(){
    //Long-running work here
}.toString(),

')()' ], { type: 'application/javascript' } ) ),

worker = new Worker( blobURL );

// Won't be needing this anymore
URL.revokeObjectURL( blobURL );

Le support est l'intersection de ces trois tables:

Cependant, cela ne fonctionnera pas pour un SharedWorker , car l'URL doit être une correspondance exacte, même si le paramètre facultatif «nom» correspond. Pour un SharedWorker, vous aurez besoin d'un fichier JavaScript distinct.


Mise à jour 2015 - La singularité ServiceWorker arrive

Il existe maintenant un moyen encore plus puissant de résoudre ce problème. Encore une fois, stockez le code de travail en tant que fonction (plutôt qu'une chaîne statique) et convertissez-le à l'aide de .toString (), puis insérez le code dans CacheStorage sous une URL statique de votre choix.

// Post code from window to ServiceWorker...
navigator.serviceWorker.controller.postMessage(
 [ '/my_workers/worker1.js', '(' + workerFunction1.toString() + ')()' ]
);

// Insert via ServiceWorker.onmessage. Or directly once window.caches is exposed
caches.open( 'myCache' ).then( function( cache )
{
 cache.put( '/my_workers/worker1.js',
  new Response( workerScript, { headers: {'content-type':'application/javascript'}})
 );
});

Il existe deux solutions de rechange possibles. ObjectURL comme ci-dessus, ou de manière plus transparente, placez un vrai fichier JavaScript dans /my_workers/worker1.js

Les avantages de cette approche sont:

  1. SharedWorkers peut également être pris en charge.
  2. Les onglets peuvent partager une seule copie en cache à une adresse fixe. L'approche blob prolifère des URL d'objet aléatoires pour chaque onglet.

4
À quoi ressemblerait la compatibilité du navigateur sur cette solution?
Ben Dilts

Pouvez-vous développer cette solution, comment ça marche? Qu'est-ce que le travailleur1.js? Est-ce un fichier js séparé? J'essaye d'utiliser ceci mais ne peux pas le faire fonctionner. Plus précisément, j'essaie de le faire fonctionner pour un SharedWorker
Yehuda

Si seulement vous pouviez l'envelopper dans une fonction utile!
mmm

@ Ben Dilts: La compatibilité du navigateur ressemblerait à simplement exécuter votre code via babel: babeljs.io/repl
Jack Giffin

La norme ne garantit pas que Function.prototype.toString () renvoie le corps de la fonction sous forme de chaîne. Vous devriez probablement ajouter un avertissement à la réponse.
RD

37

Vous pouvez créer un fichier JavaScript unique qui connaît son contexte d'exécution et peut agir à la fois comme script parent et comme travailleur. Commençons par une structure de base pour un fichier comme celui-ci:

(function(global) {
    var is_worker = !this.document;
    var script_path = is_worker ? null : (function() {
        // append random number and time to ID
        var id = (Math.random()+''+(+new Date)).substring(2);
        document.write('<script id="wts' + id + '"></script>');
        return document.getElementById('wts' + id).
            previousSibling.src;
    })();
    function msg_parent(e) {
        // event handler for parent -> worker messages
    }
    function msg_worker(e) {
        // event handler for worker -> parent messages
    }
    function new_worker() {
        var w = new Worker(script_path);
        w.addEventListener('message', msg_worker, false);
        return w;
    }
    if (is_worker)
        global.addEventListener('message', msg_parent, false);

    // put the rest of your library here
    // to spawn a worker, use new_worker()
})(this);

Comme vous pouvez le voir, le script contient tout le code du point de vue du parent et du travailleur, vérifiant si sa propre instance individuelle est un travailleur avec !document. Le script_pathcalcul quelque peu compliqué est utilisé pour calculer avec précision le chemin d'accès du script par rapport à la page parent, car le chemin d'accès fourni new Workerest relatif à la page parent, pas au script.


4
Votre site semble avoir disparu; avez-vous une nouvelle URL?
BrianFreud

1
Il s'agit d'une approche intéressante. FWIW, je détecte les Web Workers en vérifiant la présence de "self" (l'objet global Web Worker) vs "window".
pwnall

J'ai étudié la façon dont PapaParse gère les travailleurs du Web et ils semblent adopter cette approche github.com/mholt/PapaParse
JP DeVries

Je pense que tester en utilisant 'typeof importScripts! == null' peut dire si le script s'exécute dans la portée du travailleur.
MeTTeO

1
Je ne comprends pas ce que le previousSibling est de l'élément script. Quelqu'un peut-il m'expliquer?
Teemoh

28

En utilisant la Blobméthode, que diriez-vous de cela pour une usine de travailleurs:

var BuildWorker = function(foo){
   var str = foo.toString()
             .match(/^\s*function\s*\(\s*\)\s*\{(([\s\S](?!\}$))*[\s\S])/)[1];
   return  new Worker(window.URL.createObjectURL(
                      new Blob([str],{type:'text/javascript'})));
}

Vous pouvez donc l'utiliser comme ça ...

var myWorker = BuildWorker(function(){
   //first line of worker
   self.onmessage(){....};
   //last line of worker
});

ÉDITER:

Je viens d'étendre cette idée pour faciliter la communication inter-threads: bridged-worker.js .

EDIT 2:

Le lien ci-dessus est vers un résumé que j'ai créé. Quelqu'un d'autre l'a transformé plus tard en un véritable repo .


11

Les travailleurs du Web opèrent dans des contextes entièrement distincts en tant que programmes individuels.

Cela signifie que le code ne peut pas être déplacé d'un contexte à un autre sous forme d'objet, car ils pourraient alors référencer des objets via des fermetures appartenant à l'autre contexte.
Ceci est particulièrement important car ECMAScript est conçu pour être un langage à thread unique, et comme les travailleurs Web opèrent dans des threads séparés, vous risquez alors d'effectuer des opérations non sécurisées pour les threads.

Cela signifie à nouveau que les travailleurs Web doivent être initialisés avec du code sous forme source.

La spécification de WHATWG dit

Si l'origine de l'URL absolue résultante n'est pas la même que l'origine du script d'entrée, lancez une exception SECURITY_ERR.

Ainsi, les scripts doivent être des fichiers externes avec le même schéma que la page d'origine: vous ne pouvez pas charger un script à partir d'une donnée: URL ou javascript: URL, et une page https: n'a pas pu démarrer les travailleurs utilisant des scripts avec http: URL.

mais malheureusement, cela n'explique pas vraiment pourquoi on ne pouvait pas permettre de passer une chaîne avec du code source au constructeur.


6

une meilleure façon de lire pour un travailleur en ligne ..

    var worker_fn = function(e) 
    {
        self.postMessage('msg from worker');            
    };

    var blob = new Blob(["onmessage ="+worker_fn.toString()], { type: "text/javascript" });

    var worker = new Worker(window.URL.createObjectURL(blob));
    worker.onmessage = function(e) 
    {
       alert(e.data);
    };
    worker.postMessage("start"); 

Ce que j'ai fait, c'est que j'ai créé une fonction avec tout le code de travail, passer cette fonction toString(), extraire le corps et ensuite le mettre dans un Blob. Vérifiez à la dernière réponse, j'ai un exemple
Fernando Carvajal

5

Prendre la réponse d'Adria et la mettre dans une fonction copier-coller qui fonctionne avec Chrome et FF actuels mais pas IE10 (le travailleur de blob provoque une erreur de sécurité ).

var newWorker = function (funcObj) {
    // Build a worker from an anonymous function body
    var blobURL = URL.createObjectURL(new Blob(
        ['(', funcObj.toString(), ')()'],
        {type: 'application/javascript'}
     ));

    var worker = new Worker(blobURL);

    // Won't be needing this anymore
    URL.revokeObjectURL(blobURL);

    return worker;
}

Et voici un exemple de travail http://jsfiddle.net/ubershmekel/YYzvr/


5

Réponse récente (2018)

Vous pouvez utiliser Greenlet :

Déplacez une fonction asynchrone dans son propre thread. Une version simplifiée à fonction unique de Workerize .

Exemple:

import greenlet from 'greenlet'

const getName = greenlet(async username => {
  const url = `https://api.github.com/users/${username}`
  const res = await fetch(url)
  const profile = await res.json()
  return profile.name
})

console.log(await getName('developit'))

3

Selon votre cas d'utilisation, vous pouvez utiliser quelque chose comme

task.js Interface simplifiée pour exécuter du code gourmand en ressources CPU sur tous les cœurs (node.js et web)

Un exemple serait

function blocking (exampleArgument) {
    // block thread
}

// turn blocking pure function into a worker task
const blockingAsync = task.wrap(blocking);

// run task on a autoscaling worker pool
blockingAsync('exampleArgumentValue').then(result => {
    // do something with result
});

2

Jetez un œil au plugin vkThread. Avec le plugin htis, vous pouvez prendre n'importe quelle fonction dans votre code principal et l'exécuter dans un thread (Web Worker). Ainsi, vous n'avez pas besoin de créer un "fichier de travail Web" spécial.

http://www.eslinstructor.net/vkthread/

--Vadim


1

Vous pouvez utiliser des travailleurs Web dans la même firme javascript en utilisant des travailleurs Web en ligne.

L'article ci-dessous vous aidera à comprendre facilement les travailleurs Web et leurs limites et le débogage des travailleurs Web.

Maîtrise des webworkers


1

Je pense que la meilleure façon de le faire est d'utiliser un objet Blob, ci-dessous vous pouvez voir un exemple simple.

// create a Blob object with a worker code
var blob = new Blob(["onmessage = function(e) { postMessage('msg from worker'); }"]);

// Obtain a blob URL reference to our worker 'file'.
var blobURL = window.URL.createObjectURL(blob);

// create a Worker
var worker = new Worker(blobURL);
worker.onmessage = function(e) {
  console.log(e.data);
};
worker.postMessage("Send some Data"); 


1

ici console:

var worker=new Worker(window.URL.createObjectURL(new Blob([function(){
  //Long-running work here
  postMessage('done');
}.toString().split('\n').slice(1,-1).join('\n')],{type:'text/javascript'})));

worker.addEventListener('message',function(event){
  console.log(event.data);
});

1

https://developer.mozilla.org/es/docs/Web/Guide/Performance/Using_web_workers

    // Syntax: asyncEval(code[, listener])

var asyncEval = (function () {

  var aListeners = [], oParser = new Worker("data:text/javascript;charset=US-ASCII,onmessage%20%3D%20function%20%28oEvent%29%20%7B%0A%09postMessage%28%7B%0A%09%09%22id%22%3A%20oEvent.data.id%2C%0A%09%09%22evaluated%22%3A%20eval%28oEvent.data.code%29%0A%09%7D%29%3B%0A%7D");

  oParser.onmessage = function (oEvent) {
    if (aListeners[oEvent.data.id]) { aListeners[oEvent.data.id](oEvent.data.evaluated); }
    delete aListeners[oEvent.data.id];
  };


  return function (sCode, fListener) {
    aListeners.push(fListener || null);
    oParser.postMessage({
      "id": aListeners.length - 1,
      "code": sCode
    });
  };

})();


1

Je pense donc que nous avons une autre option intéressante pour cela maintenant, grâce aux modèles de littéraux dans ES6. Cela nous permet de nous passer de la fonction de travail supplémentaire (et de sa portée étrange) et d'écrire simplement le code qui est destiné au travailleur en tant que texte multiligne, un peu comme dans le cas où nous utilisions pour stocker du texte, mais sans avoir réellement besoin d'un document ou d'un DOM pour le faire. Exemple:

const workerScript = `
self.addEventListener('message', function(e) {
  var data = e.data;
  console.log('worker recieved: ',data);
  self.postMessage('worker added! :'+ addOne(data.value));
  self.close();//kills the worker
}, false);
`;

Voici un aperçu du reste de cette approche .

Notez que nous pouvons insérer toutes les dépendances de fonction supplémentaires que nous voulons dans le travailleur simplement en les collectant dans un tableau et en exécutant .toString sur chacune d'entre elles pour les réduire également en chaînes (cela devrait fonctionner tant qu'elles sont des déclarations de fonction) et puis en ajoutant simplement cela à la chaîne de script. De cette façon, nous n'avons pas à importer des scripts que nous pourrions déjà avoir inclus dans la portée du code que nous écrivons.

Le seul véritable inconvénient de cette version particulière est que les linters ne seront pas en mesure de linter le code du service worker (car il ne s'agit que d'une chaîne), ce qui est un avantage pour "l'approche de fonction de travail séparée".


1

Ce n'est qu'un ajout à ce qui précède - j'ai de beaux modèles pour tester les travailleurs Web dans jsFiddle. Plutôt que Blob, il utilise l'API jsFiddles ?js:

function workerFN() {
  self.onmessage = function(e) {
    switch(e.data.name) {
      case "" : 
      break;
      default:
        console.error("Unknown message:", e.data.name);
    }
  }
}
// This is a trick to generate real worker script that is loaded from server
var url = "/echo/js/?js="+encodeURIComponent("("+workerFN.toString()+")()");
var worker = new Worker(url);
worker.addEventListener("message", function(e) {
  switch(e.data.name) {
    case "" : 
    break;
    default:
      console.error("Unknown message:", e.data.name);
  }
})

Des modèles de travailleur Web normal et de travailleur partagé sont disponibles.


1

J'ai découvert que CodePen actuellement ne met pas en évidence la syntaxe des <script>balises en ligne qui ne le sont pas type="text/javascript"(ou qui n'ont pas d'attribut de type).

J'ai donc imaginé une solution similaire mais légèrement différente en utilisant des blocs étiquetés avec break, qui est le seul moyen de libérer une <script>balise sans créer de fonction wrapper (ce qui n'est pas nécessaire).

<!DOCTYPE html>
<script id="worker1">
  worker: { // Labeled block wrapper

    if (typeof window === 'object') break worker; // Bail if we're not a Worker

    self.onmessage = function(e) {
      self.postMessage('msg from worker');
    };
    // Rest of your worker code goes here.
  }
</script>
<script>
  var blob = new Blob([
    document.querySelector('#worker1').textContent
  ], { type: "text/javascript" })

  // Note: window.webkitURL.createObjectURL() in Chrome 10+.
  var worker = new Worker(window.URL.createObjectURL(blob));
  worker.onmessage = function(e) {
    console.log("Received: " + e.data);
  }
  worker.postMessage("hello"); // Start the worker.
</script>


1

Une version simple promis Function#callAsWorker, qui prend un thisArg et des arguments (comme call), et retourne une promesse:

Function.prototype.callAsWorker = function (...args) {
    return new Promise( (resolve, reject) => {
        const code = `self.onmessage = e => self.postMessage((${this.toString()}).call(...e.data));`,
            blob = new Blob([code], { type: "text/javascript" }),
            worker = new Worker(window.URL.createObjectURL(blob));
        worker.onmessage = e => (resolve(e.data), worker.terminate());
        worker.onerror = e => (reject(e.message), worker.terminate());
        worker.postMessage(args);
    });
}

// Demo
function add(...nums) {
    return nums.reduce( (a,b) => a+b );
}
// Let the worker execute the above function, with the specified arguments
add.callAsWorker(null, 1, 2, 3).then(function (result) {
    console.log('result: ', result);
});


vous devez ajouter une close()méthode pour fermer votre hook de vie de travailleur Web. developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/…
Shahar ド ー ン Levi

@Shahar ド ー ン Levi, la closefonction est déconseillée. Cependant, les travailleurs peuvent être licenciés . Je l'ai ajouté maintenant.
trincot

0

J'utilise du code comme celui-ci, vous pouvez définir votre onmessage comme une fonction autre que du texte brut, afin que l'éditeur puisse mettre en évidence votre code et vos travaux jshint.

const worker = createWorker();

createWorker() {
    const scriptContent = getWorkerScript();
    const blob = new Blob([
        scriptContent,
    ], {
        type: "text/javascipt"
    });
    const worker = new Worker(window.URL.createObjectURL(blob));
    return worker;
}

getWorkerScript() {
    const script = {
        onmessage: function (e) {
            console.log(e);
            let result = "Hello " + e.data
            postMessage(result);
        }
    };
    let content = "";
    for (let prop in script){
        content += `${prop}=${script[prop].toString()}`;
    }
    return content;
}


Regardez ma réponse , je viens de le faire, mais j'ai écrit toute une classe pour résumer comment passer les rappels
Fernando Carvajal

0

Oui, c'est possible, je l'ai fait en utilisant des fichiers Blob et en passant un rappel

Je vais vous montrer ce que fait une classe que j'ai écrite et comment elle gère l'exécution des rappels en arrière-plan.

D'abord, vous instanciez le GenericWebWorkeravec toutes les données que vous souhaitez transmettre au rappel qui sera exécuté dans le Web Worker, qui comprend les fonctions que vous souhaitez utiliser, dans ce cas un nombre, une date et une fonction appeléeblocker

var worker = new GenericWebWorker(100, new Date(), blocker)

Cette fonction de blocage exécutera un infini pendant n millisecondes

function blocker (ms) {
    var now = new Date().getTime();
    while(true) {
        if (new Date().getTime() > now +ms)
            return;
    }   
}

puis vous l'utilisez comme ça

worker.exec((num, date, fnBlocker) => {
    /*Everithing here does not block the main thread
      and this callback has access to the number, date and the blocker */
    fnBlocker(10000) //All of this run in backgrownd
    return num*10

}).then(d => console.log(d)) //Print 1000

Maintenant, il est temps de voir la magie dans l'exemple ci-dessous

/*https://github.com/fercarvo/GenericWebWorker*/
class GenericWebWorker {
    constructor(...ags) {
        this.args = ags.map(a => (typeof a == 'function') ? {type:'fn', fn:a.toString()} : a)
    }

    async exec(cb) {
        var wk_string = this.worker.toString();
        wk_string = wk_string.substring(wk_string.indexOf('{') + 1, wk_string.lastIndexOf('}'));            
        var wk_link = window.URL.createObjectURL( new Blob([ wk_string ]) );
        var wk = new Worker(wk_link);

        wk.postMessage({ callback: cb.toString(), args: this.args });
 
        var resultado = await new Promise((next, error) => {
            wk.onmessage = e => (e.data && e.data.error) ? error(e.data.error) : next(e.data);
            wk.onerror = e => error(e.message);
        })

        wk.terminate(); window.URL.revokeObjectURL(wk_link);
        return resultado
    }

    async parallel(arr, cb) {
        var res = [...arr].map(it => new GenericWebWorker(it, ...this.args).exec(cb))
        var all = await Promise.all(res)
        return all
    }

    worker() {
        onmessage = async function (e) {
            try {                
                var cb = new Function(`return ${e.data.callback}`)();
                var args = e.data.args.map(p => (p.type == 'fn') ? new Function(`return ${p.fn}`)() : p);

                try {
                    var result = await cb.apply(this, args); //If it is a promise or async function
                    return postMessage(result)

                } catch (e) { throw new Error(`CallbackError: ${e}`) }
            } catch (e) { postMessage({error: e.message}) }
        }
    }
}


function blocker (ms) {
    var now = new Date().getTime();
    while(true) {
        if (new Date().getTime() > now +ms)
            return;
    }   
}

setInterval(()=> console.log("Not blocked " + Math.random()), 1000)

console.log("\n\nstarting blocking code in Worker\n\n")

var worker = new GenericWebWorker(100, new Date(), blocker)

worker.exec((num, date, fnBlocker) => {
    fnBlocker(7000) //All of this run in backgrownd
    return num*10    
})
.then(d => console.log(`\n\nEnd of blocking code: result ${d}\n\n`)) //Print 1000


0

Vous pouvez placer le contenu de votre fichier worker.js à l'intérieur de backticks (ce qui permet une constante de chaîne multiligne) et créer le travailleur à partir d'un blob comme ceci:

var workerScript = `
    self.onmessage = function(e) {
        self.postMessage('message from worker');
    };
    // rest of worker code goes here
`;

var worker =
    new Worker(createObjectURL(new Blob([workerScript], { type: "text/javascript" })));

C'est pratique si, pour une raison quelconque, vous ne voulez pas avoir de balises de script distinctes pour le travailleur.


0

Une autre solution consiste simplement à envelopper le Worker dans une fonction, puis à créer un blob appelant la fonction comme suit:

     function workerCode() {
        self.onmessage = function (e) {
          console.log("Got message from parent", e.data);
        };
        setTimeout(() => {
          self.postMessage("Message From Worker");
        }, 2000);
      }

      let blob = new Blob([
        "(" + workerCode.toString() + ")()"
      ], {type: "text/javascript"});

      // Note: window.webkitURL.createObjectURL() in Chrome 10+.
      let worker = new Worker(window.URL.createObjectURL(blob));
      worker.onmessage = function (e) {
        console.log("Received: " + e.data);
      };
      worker.postMessage("hello"); // Start the worker.

-1

One-liner pour exécuter des fonctions chez les travailleurs:

const FunctionalWorker = fn => new Worker(window.URL.createObjectURL(new Blob(["(" + workerCode.toString() + ")()"], {type: "text/javascript"})));

Exemple d'utilisation:

let fn = FunctionalWorker(() => {
    self.postMessage("hi");
});
fn.onmessage = msg => {
    console.log(msg);
};
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.