Pekerja web tanpa file Javascript terpisah?

291

Sejauh yang saya tahu, pekerja web harus ditulis dalam file JavaScript terpisah, dan dipanggil seperti ini:

new Worker('longrunning.js')

Saya menggunakan kompilator penutupan untuk menggabungkan dan mengurangi semua kode sumber JavaScript saya, dan saya lebih suka tidak perlu pekerja saya di file terpisah untuk distribusi. Apakah ada cara untuk melakukan ini?

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

Mengingat bahwa fungsi kelas satu sangat penting untuk JavaScript, mengapa cara standar untuk melakukan pekerjaan latar belakang harus memuat seluruh file JavaScript lain dari server web?

Ben Dilts
sumber
7
Itu karena menjaga konteks eksekusi murni threadsafe bahkan lebih penting daripada fungsi kelas satu :-)
Pointy
1
Saya sedang mengusahakannya (atau lebih tepatnya meminimalkan masalah): DynWorker . Anda dapat melakukan: var worker = new DynWorker(); worker.inject("foo", function(){...});...
Félix Saparelli
1
OP menghapus pertanyaan "Pekerja Pengajar untuk menerima fungsi alih-alih file sumber JavaScript". Jawabannya diposting kembali di sini
Rob W
Saya mengembangkan task.js untuk membuatnya lebih mudah dilakukan. Sebagian besar waktu Anda hanya mencoba membongkar tugas penguncian kecil.
Chad Scira

Jawaban:

225

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

Bagaimana jika Anda ingin membuat skrip pekerja Anda dengan cepat, atau membuat halaman mandiri tanpa harus membuat file pekerja terpisah? Dengan Blob (), Anda dapat "inline" pekerja Anda dalam file HTML yang sama dengan logika utama Anda dengan membuat pegangan URL ke kode pekerja sebagai string


Contoh lengkap dari pekerja inline 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>

vsync
sumber
Google Chrome saja solusinya, tampaknya Firefox 10 akan mendukungnya, saya tidak tahu tentang peramban lain
4esn0k
2
BlobBuiler sekarang sudah tidak digunakan lagi . Gunakan Blob sebagai gantinya. Saat ini didukung di Firefox / WebKit / Opera dan IE10 terbaru, lihat tabel kompatibilitas untuk browser lama.
Félix Saparelli
3
Konstruktor Blob mungkin didukung di IE10, tetapi Anda masih tidak dapat meneruskan javascript ke pekerja web melaluinya (bahkan di IE11): connect.microsoft.com/IE/feedback/details/801810/… .
jayarjo
1
@albanx -Apa tes? sudah ada miliar halaman demo online yang menunjukkan bahwa threading tidak menutup-nutupi browser selama bertahun-tahun.
vsync
2
@albanx - maukah Anda setidaknya mengatakan browser esoteris mana yang Anda gunakan yang hang? apakah demo ini hang untuk Anda? ie.microsoft.com/testdrive/Graphics/WorkerFountains/…
vsync
162

Solusi html5rocks menanamkan kode pekerja web dalam HTML cukup mengerikan.
Dan gumpalan JavaScript-as-a-string yang lolos tidak lebih baik, paling tidak karena mempersulit alur kerja (Compiler Closure tidak dapat beroperasi pada string).

Secara pribadi saya sangat suka metode toString, tapi @ dan-man regex ITU!

Pendekatan pilihan saya:

// 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 );

Dukungan adalah persimpangan dari tiga tabel ini:

Ini tidak akan berfungsi untuk SharedWorker , karena URL harus sama persis, bahkan jika parameter 'nama' opsional cocok. Untuk SharedWorker, Anda memerlukan file JavaScript terpisah.


Pembaruan 2015 - Singularitas ServiceWorker tiba

Sekarang ada cara yang lebih kuat untuk menyelesaikan masalah ini. Sekali lagi, simpan kode pekerja sebagai fungsi, (bukan string statis) dan konversikan menggunakan .toString (), lalu masukkan kode ke dalam CacheStorage di bawah URL statis pilihan Anda.

// 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'}})
 );
});

Ada dua kemungkinan mundur. ObjectURL seperti di atas, atau lebih tepatnya, menempatkan a file JavaScript nyata di /my_workers/worker1.js

Keuntungan dari pendekatan ini adalah:

  1. SharedWorkers juga dapat didukung.
  2. Tab dapat membagikan satu salinan dalam tembolok pada alamat tetap. Pendekatan blob memperbanyak objekURUR acak untuk setiap tab.
Adria
sumber
4
Akan seperti apa kompatibilitas browser pada solusi ini?
Ben Dilts
Bisakah Anda menguraikan solusi ini, bagaimana cara kerjanya? Apa pekerja itu? Apakah ini file js terpisah? Saya mencoba menggunakan ini tetapi tidak dapat membuatnya berfungsi. Secara khusus saya mencoba membuatnya bekerja untuk SharedWorker
Yehuda
Kalau saja Anda bisa membungkusnya dalam fungsi yang bermanfaat!
mmm
@ Ben Dilts: Kompatibilitas browser akan terlihat seperti hanya menjalankan kode Anda melalui babel: babeljs.io/repl
Jack Giffin
Standar tidak menjamin bahwa Function.prototype.toString () mengembalikan tubuh fungsi sebagai string. Anda mungkin harus menambahkan peringatan ke jawabannya.
RD
37

Anda dapat membuat satu file JavaScript yang mengetahui konteks eksekusi dan dapat bertindak sebagai skrip induk dan pekerja. Mari kita mulai dengan struktur dasar untuk file seperti ini:

(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);

Seperti yang Anda lihat, skrip berisi semua kode untuk sudut pandang orang tua dan pekerja, memeriksa apakah instans individualnya adalah seorang pekerja !document. script_pathKomputasi yang agak sulit digunakan untuk secara akurat menghitung jalur skrip relatif terhadap halaman induk, karena jalur yang disediakan new Workerrelatif terhadap halaman induk, bukan skrip.

Delan Azabani
sumber
4
Situs Anda tampaknya telah menghilang; apakah Anda memiliki URL baru?
BrianFreud
1
Ini merupakan pendekatan yang menarik. FWIW, saya fitur-mendeteksi Pekerja Web dengan memeriksa keberadaan "diri" (objek global Pekerja Web) vs "jendela".
pwnall
Saya telah melihat ke dalam bagaimana PapaParse menangani Pekerja Web dan mereka tampaknya mengambil pendekatan ini github.com/mholt/PapaParse
JP DeVries
Saya pikir pengujian menggunakan 'typeof importScripts! == null' dapat mengetahui apakah skrip berjalan dalam lingkup pekerja.
MeTTeO
1
Saya tidak mengerti apa yang sebelumnya adalah dari elemen-script. Bisakah seseorang menjelaskan saya?
Teemoh
28

Dengan menggunakan Blobmetode ini, bagaimana dengan ini untuk pabrik pekerja:

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'})));
}

Jadi Anda bisa menggunakannya seperti ini ...

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

EDIT:

Saya baru saja memperluas ide ini lebih lanjut untuk membuatnya lebih mudah untuk melakukan komunikasi cross-thread: bridged-worker.js .

EDIT 2:

Tautan di atas adalah ke intisari yang saya buat. Orang lain kemudian mengubahnya menjadi repo yang sebenarnya .

dan-man
sumber
11

Pekerja web beroperasi dalam konteks yang sepenuhnya terpisah sebagai Program individual.

Ini berarti bahwa kode tidak dapat dipindahkan dari satu konteks ke konteks lain dalam bentuk objek, karena mereka kemudian dapat mereferensikan objek melalui penutupan milik konteks lain.
Ini sangat penting karena ECMAScript dirancang untuk menjadi bahasa utas tunggal, dan karena pekerja web beroperasi di utas terpisah, Anda kemudian akan berisiko operasi yang tidak aman dilakukan.

Ini lagi berarti bahwa pekerja web perlu diinisialisasi dengan kode dalam bentuk sumber.

Spesifikasi dari WHATWG mengatakan

Jika asal URL absolut yang dihasilkan tidak sama dengan asal skrip entri, maka lontarkan pengecualian SECURITY_ERR.

Dengan demikian, skrip harus berupa file eksternal dengan skema yang sama dengan halaman asli: Anda tidak dapat memuat skrip dari data: URL atau javascript: URL, dan halaman https: tidak dapat memulai pekerja menggunakan skrip dengan http: URL.

tetapi sayangnya itu tidak benar-benar menjelaskan mengapa seseorang tidak bisa membiarkan melewati string dengan kode sumber ke konstruktor.

Sean Kinsey
sumber
6

cara yang lebih baik untuk membaca bagi pekerja inline ..

    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"); 
Chris Tobba
sumber
Apa yang saya lakukan adalah bahwa saya membuat fungsi dengan semua kode pekerja, meneruskan fungsi itu toString(), mengekstrak tubuh dan kemudian memasukkannya ke dalam Gumpalan. Periksa jawaban terakhir, saya punya contoh
Fernando Carvajal
5

Mengambil respons Adria dan menempatkannya dalam fungsi copy-pastable yang bekerja dengan Chrome dan FF saat ini tetapi tidak dengan IE10 (pekerja dari gumpalan menyebabkan kesalahan keamanan ).

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;
}

Dan inilah contoh yang berfungsi http://jsfiddle.net/ubershmekel/YYzvr/

ubershmekel
sumber
5

Jawaban terakhir (2018)

Anda dapat menggunakan Greenlet :

Pindahkan fungsi async ke utasnya sendiri. Versi Workerize fungsi tunggal yang disederhanakan .

Contoh:

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'))
GG.
sumber
3

Tergantung pada kasus penggunaan Anda, Anda dapat menggunakan sesuatu seperti

task.js Antarmuka yang disederhanakan untuk mendapatkan kode intensif CPU untuk berjalan di semua core (node.js, dan web)

Contohnya adalah

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
});
Chad Scira
sumber
2

Lihatlah plugin vkThread. Dengan plugin htis Anda dapat mengambil fungsi apa pun dalam kode utama Anda dan menjalankannya di utas (pekerja web). Jadi, Anda tidak perlu membuat "file pekerja web" khusus.

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

--Adim

vadimk
sumber
1

Anda dapat menggunakan pekerja web di javascript yang sama menggunakan inwork web inline.

Artikel di bawah ini akan membahas Anda untuk dengan mudah memahami webworkers dan batasannya serta debugging webworkers.

Menguasai pekerja web

Kirankumar
sumber
1

Saya pikir cara yang lebih baik untuk melakukan ini adalah menggunakan objek Blob, di bawah ini Anda dapat melihat contoh sederhana.

// 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"); 
Miguel Q.
sumber
1

Coba gunakan jThread. https://github.com/cheprasov/jThread

// You can use simple calling like this
jThread(
    function(arr){
        //... some code for Worker
        return arr;
    }
    ,function(arr){
        //... done code
    }
)( [1,2,3,4,5,6,7] ); // some params
Alexander Cheprasov
sumber
1

di sini konsol:

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);
});
59naga
sumber
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
    });
  };

})();
hamboy75
sumber
1

Gunakan plugin kecil saya https://github.com/zevero/worker-create

var worker_url = Worker.createURL(function(e){
  self.postMessage('Example post from Worker'); //your code here
});
var worker = new Worker(worker_url);
zevero
sumber
1

Jadi saya pikir kami memiliki opsi keren lain untuk ini sekarang, terima kasih untuk templat literal di ES6. Itu memungkinkan kita untuk membuang fungsi pekerja tambahan (dan ruang lingkup yang aneh) dan hanya menulis kode yang dimaksudkan untuk pekerja sebagai teks multiline, seperti halnya kasus yang kami gunakan untuk menyimpan teks, tetapi tanpa benar-benar membutuhkan dokumen atau DOM untuk melakukannya. Contoh:

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);
`;

Inilah inti dari sisa pendekatan itu .

Perhatikan bahwa kita dapat menarik dependensi fungsi tambahan apa pun yang kita inginkan ke dalam pekerja hanya dengan mengumpulkan mereka ke dalam array dan menjalankan .toString pada masing-masing untuk mengurangi mereka menjadi string juga (harus bekerja selama mereka adalah deklarasi fungsi) dan kemudian hanya menambahkannya ke skrip string. Dengan begitu kita tidak perlu mengimpor Script yang mungkin sudah kita bundel ke dalam lingkup kode yang kita tulis.

Satu-satunya downside nyata untuk versi khusus ini adalah bahwa linter tidak akan dapat lint kode pekerja layanan (karena itu hanya string), yang merupakan keuntungan untuk "pendekatan fungsi pekerja terpisah."

Dtipson
sumber
1

Ini hanya tambahan di atas - Saya punya template yang bagus untuk menguji pekerja web di jsFiddle. Daripada Blob ia menggunakan ?jsapi jsFiddles :

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);
  }
})

Templat web pekerja normal dan templat pekerja bersama tersedia.

Tomáš Zato - Pasang kembali Monica
sumber
1

Saya menemukan bahwa CodePen saat ini tidak menggunakan <script>tag inline sintaks-highlight yang bukan type="text/javascript"(atau yang tidak memiliki atribut tipe).

Jadi saya menemukan solusi serupa tetapi sedikit berbeda menggunakan blok berlabel dengan break, yang merupakan satu-satunya cara Anda dapat menebus dari <script>tag tanpa membuat fungsi pembungkus (yang tidak perlu).

<!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>

msanford
sumber
1

Versi yang dijanjikan sederhana,, Function#callAsWorkeryang mengambil thisArg dan argumen (sama seperti call), dan mengembalikan janji:

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);
});

trincot
sumber
Anda harus menambahkan close()metode untuk menutup kait kehidupan pekerja web Anda. developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/…
Shahar ド ー ン Levi
@ Shahar ド ー ン Levi, closefungsinya sudah usang. Namun, pekerja dapat diberhentikan . Saya telah menambahkan itu sekarang.
trincot
0

Saya menggunakan kode seperti ini, Anda dapat mendefinisikan onmessage Anda sebagai fungsi selain teks biasa, sehingga editor dapat menyoroti kode Anda dan jshint berfungsi.

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;
}

Z.JC
sumber
Lihatlah jawaban saya , saya baru saja melakukannya tetapi saya menulis seluruh kelas untuk mengabstraksi cara menyampaikan panggilan balik
Fernando Carvajal
0

Ya, itu mungkin, saya melakukannya menggunakan file Blob dan meneruskan panggilan balik

Saya akan menunjukkan kepada Anda apa yang dilakukan kelas yang saya tulis dan bagaimana mengelola eksekusi callback di latar belakang.

Pertama, Anda instantiate GenericWebWorkerdengan data apa pun yang ingin Anda sampaikan ke panggilan balik yang akan dijalankan di Web Worker, yang mencakup fungsi yang ingin Anda gunakan, dalam hal ini angka, tanggal dan fungsi yang disebutblocker

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

Fungsi pemblokir ini akan mengeksekusi infinite while selama n miliseconds

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

dan kemudian Anda menggunakannya seperti ini

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

Sekarang, saatnya untuk melihat keajaiban pada contoh di bawah ini

/*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

Fernando Carvajal
sumber
0

Anda dapat menempatkan konten file worker.js Anda di dalam backticks (yang memungkinkan konstanta string multiline) dan membuat pekerja dari gumpalan seperti ini:

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" })));

Ini berguna jika karena alasan apa pun Anda tidak ingin memiliki tag skrip terpisah untuk pekerja.

samgak
sumber
0

Solusi lain adalah hanya dengan membungkus Pekerja dalam suatu fungsi, kemudian membuat gumpalan yang memanggil fungsi seperti:

     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.
Shlomi Schwartz
sumber
-1

One-liner untuk menjalankan fungsi pada pekerja:

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

Contoh penggunaan:

let fn = FunctionalWorker(() => {
    self.postMessage("hi");
});
fn.onmessage = msg => {
    console.log(msg);
};
ifeelbadformyoldquestions
sumber