स्ट्रिंग से वेब वर्कर कैसे बनाएं


84

मैं एक स्ट्रिंग से एक वेब कार्यकर्ता कैसे बना सकता हूं (जो एक पोस्ट अनुरोध के माध्यम से आपूर्ति की जाती है)?

एक ऐसा तरीका जिसके बारे में मैं सोच सकता हूं, लेकिन मुझे यकीन नहीं है कि इसे कैसे लागू किया जाए, यह सर्वर प्रतिक्रिया से एक डेटा-यूआरआई बनाकर है और जो कि वर्कर कंस्ट्रक्टर को दे रहा है, लेकिन मैंने सुना है कि कुछ ब्राउज़र अनुमति नहीं देते हैं यह उसी मूल नीति के कारण है।

MDN डेटा URI के आसपास मूल नीति के बारे में अनिश्चितता बताता है :

नोट: श्रमिक निर्माणकर्ता के पैरामीटर के रूप में पारित URI को उसी मूल नीति का पालन करना चाहिए। वर्तमान में ब्राउज़रों विक्रेताओं में इस बात पर असहमति है कि क्या डेटा यूआरआई एक ही मूल के हैं या नहीं; गेको 10.0 (फ़ायरफ़ॉक्स 10.0 / थंडरबर्ड 10.0) और बाद में श्रमिकों के लिए एक वैध स्क्रिप्ट के रूप में डेटा यूआरआई की अनुमति देता है। अन्य ब्राउज़र असहमत हो सकते हैं।

यहाँ व्हाट्सएप पर इसकी चर्चा करते हुए एक पोस्ट भी है ।


मुझे आश्चर्य है कि अगर कोर ( w3.org/TR/cors ) मदद करेगा। HTMl5rocks मज़बूत "मस्ट" भाषा का उपयोग करते हैं, जब श्रमिकों ( html5rocks.com/en/tutorials/workers/basics ) के लिए समान मूल नीति की बात आती है, तो हो सकता है कि CORS यहाँ बहुत मदद का नहीं है। क्या आपने इसे आजमाया?
पावेल वेलर

जवाबों:


146

सारांश

  • blob: Chrome के लिए 8+, फ़ायरफ़ॉक्स 6+, सफारी 6.0+, ओपेरा 15+
  • data:application/javascript ओपेरा के लिए 10.60 - 12
  • eval अन्यथा (IE 10+)

URL.createObjectURL(<Blob blob>)एक स्ट्रिंग से वेब कार्यकर्ता बनाने के लिए इस्तेमाल किया जा सकता है। बूँद को BlobBuilderएपीआई पदावनत या Blobनिर्माणकर्ता का उपयोग करके बनाया जा सकता है ।

डेमो: http://jsfiddle.net/uqcFM/49/

// URL.createObjectURL
window.URL = window.URL || window.webkitURL;

// "Server response", used in all examples
var response = "self.onmessage=function(e){postMessage('Worker: '+e.data);}";

var blob;
try {
    blob = new Blob([response], {type: 'application/javascript'});
} catch (e) { // Backwards-compatibility
    window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
    blob = new BlobBuilder();
    blob.append(response);
    blob = blob.getBlob();
}
var worker = new Worker(URL.createObjectURL(blob));

// Test, used in all examples:
worker.onmessage = function(e) {
    alert('Response: ' + e.data);
};
worker.postMessage('Test');

अनुकूलता

वेब कर्मचारियों को निम्नलिखित ब्राउज़र स्रोत में समर्थित किया जाता है :

  • क्रोम 3
  • फ़ायरफ़ॉक्स 3.5
  • IE 10
  • ओपेरा 10.60
  • सफ़ारी ४

इस विधि का समर्थन Blobएपीआई और विधि के समर्थन पर आधारित है URL.createObjectUrlBlobअनुकूलता :

  • Chrome 8+ ( WebKitBlobBuilder), 20+ ( Blobनिर्माता)
  • फ़ायरफ़ॉक्स 6+ ( MozBlobBuilder), 13+ ( Blobकंस्ट्रक्टर)
  • सफारी 6+ ( Blobनिर्माता)

IE10 का समर्थन करता है MSBlobBuilderऔर URL.createObjectURL। हालाँकि, blob:-URL से वेब वर्कर बनाने का प्रयास एक SecurityError फेंकता है।

ओपेरा 12 URLएपीआई का समर्थन नहीं करता है। कुछ उपयोगकर्ताओं के पास इस हैक केURL लिए धन्यवाद, ऑब्जेक्ट का एक नकली संस्करण हो सकता है ।browser.js

फालबैक 1: डेटा-यूआरआई

ओपेरा Workerकंस्ट्रक्टर के तर्क के रूप में डेटा-यूआरआई का समर्थन करता है । नोट: विशेष वर्ण (जैसे कि #और %) से बचने के लिए मत भूलना ।

// response as defined in the first example
var worker = new Worker('data:application/javascript,' +
                        encodeURIComponent(response) );
// ... Test as defined in the first example

डेमो: http://jsfiddle.net/uqcFM/37/

फॉलबैक 2: एवल

eval सफारी (<6) और IE 10 के लिए एक वापसी के रूप में इस्तेमाल किया जा सकता है।

// Worker-helper.js
self.onmessage = function(e) {
    self.onmessage = null; // Clean-up
    eval(e.data);
};
// Usage:
var worker = new Worker('Worker-helper.js');
// `response` as defined in the first example
worker.postMessage(response);
// .. Test as defined in the first example

3
@BrianFreid आपके संपादन के लिए धन्यवाद, लेकिन इसकी आवश्यकता नहीं है। यदि आप आगे कुछ पंक्तियाँ देखते हैं, तो आपको "IE10 समर्थन MSBlobBuilderऔर URL.createObjectURL। हालांकि, एक blob:-URL से एक वेब वर्कर बनाने की कोशिश कर रहा है एक SecurityError फेंकता है।" तो, जोड़ने MSBlobBuilderका कोई प्रभाव नहीं होगा, एकमात्र विकल्प # 2 है।
Rob W

ओपेरा 12 अब परिभाषित नहीं करता है URL(और इसलिए न तो उस पर किसी भी गुण को परिभाषित करता है), और ब्लॉब निर्माता आजकल पर्याप्त रूप से समर्थित है।
gsnedders

2
मैंने सत्यापित किया है कि यह अभी भी IE11 में होता है, कम से कम पूर्वावलोकन में।
बेंजामिन ग्रुएनबाम

1
क्या dataURI केवल ओपेरा या अन्य सभी ब्राउज़रों (IE को छोड़कर) में समर्थित हैं?
जयरजो

1
वेबकर्मियों के data:लिए @jayarjo -URI फ़ायरफ़ॉक्स में समर्थित हैं, लेकिन क्रोम या ओपेरा 15+ में नहीं। का प्रदर्शन evalप्रासंगिक नहीं है, आप प्रति सेकंड लाखों वेब कार्यकर्ता बनाने नहीं जा रहे हैं।
रॉब डब्ल्यू

12

मैं वर्तमान स्वीकृत उत्तर से सहमत हूं लेकिन अक्सर कार्यकर्ता कोड का संपादन और प्रबंधन एक स्ट्रिंग के रूप में व्यस्त होगा।

इसलिए वैकल्पिक रूप से हम नीचे दिए गए दृष्टिकोण का उपयोग कर सकते हैं जहां हम कार्यकर्ता को एक फ़ंक्शन के रूप में रख सकते हैं, और फिर स्ट्रिंग-> ब्लॉब को गुप्त कर सकते हैं:

// function to be your worker
function workerFunction() {
    var self = this;
    self.onmessage = function(e) {
        console.log('Received input: ', e.data); // message received from main thread
        self.postMessage("Response back to main thread");
    }
}


///////////////////////////////

var dataObj = '(' + workerFunction + ')();'; // here is the trick to convert the above fucntion to string
var blob = new Blob([dataObj.replace('"use strict";', '')]); // firefox adds "use strict"; to any function which might block worker execution so knock it off

var blobURL = (window.URL ? URL : webkitURL).createObjectURL(blob, {
    type: 'application/javascript; charset=utf-8'
});


var worker = new Worker(blobURL); // spawn new worker

worker.onmessage = function(e) {
    console.log('Worker said: ', e.data); // message received from worker
};
worker.postMessage("some input to worker"); // Send data to our worker.

यह IE11 + और FF और क्रोम में परीक्षण किया गया है


1
@SenJacob जैसा कि यह एक सामुदायिक विकि पोस्ट नहीं है, आपको एक संपादन के बजाय एक टिप्पणी के माध्यम से पोस्टर के संभावित मुद्दों को उजागर करना चाहिए।
गुडबाय StackExchange

@FrankerZ क्षमा करें। मुझे इसे IE11 में काम करना पड़ा जिसमें मैंने जो बदलाव किए हैं। @ ChanuSukarno क्या आप जाँच सकते हैं कि क्या संशोधन 3 में परिवर्तन ठीक है?
सेन जैकब

FYI करें, "प्रकार: 'एप्लिकेशन / जावास्क्रिप्ट; चारसेट = utf-8'" ब्लॉब निर्माता में है, न कि createObjectURL कॉल।
सोरा २४५५

तो ... आप अपने कार्यकर्ता के बाहर एक समारोह का निर्माण कर रहे हैं, बस इसे अपने पाठ संपादक में बेहतर पढ़ने के लिए? क्या बकवास है। आपको बिना किसी कारण के उस फ़ंक्शन को दो संदर्भों में मेमोरी में लोड करना होगा।
ADJenks

4

मैंने आपके अधिकांश विचारों के साथ एक दृष्टिकोण बनाया है और कुछ को जोड़ रहा हूं। कार्यकर्ता पर मेरे कोड की एकमात्र आवश्यकता 'स्व' के दायरे को संदर्भित करने के लिए 'इस' का उपयोग करना है। मुझे पूरा यकीन है कि यह बहुत कामचलाऊ है:

// Sample code
var code = function() {
    this.onmessage = function(e) {
        this.postMessage('Worker: '+e.data);
        this.postMessage('Worker2: '+e.data);
    };
};

// New thread worker code
FakeWorkerCode = function(code, worker) {
    code.call(this);
    this.worker = worker;
}
FakeWorkerCode.prototype.postMessage = function(e) {
    this.worker.onmessage({data: e});
}
// Main thread worker side
FakeWorker = function(code) {
    this.code = new FakeWorkerCode(code, this);
}
FakeWorker.prototype.postMessage = function(e) {
    this.code.onmessage({data: e});
}

// Utilities for generating workers
Utils = {
    stringifyFunction: function(func) {
        // Stringify the code
        return '(' + func + ').call(self);';
    },
    generateWorker: function(code) {
        // URL.createObjectURL
        windowURL = window.URL || window.webkitURL;   
        var blob, worker;
        var stringified = Utils.stringifyFunction(code);
        try {
            blob = new Blob([stringified], {type: 'application/javascript'});
        } catch (e) { // Backwards-compatibility
            window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
            blob = new BlobBuilder();
            blob.append(stringified);
            blob = blob.getBlob();
        }

        if ("Worker" in window) {
            worker = new Worker(windowURL.createObjectURL(blob));
        } else {
            worker = new FakeWorker(code);
        }
        return worker;
    }
};

// Generate worker
var worker = Utils.generateWorker(code);
// Test, used in all examples:
worker.onmessage = function(e) {
    alert('Response: ' + e.data);
};
function runWorker() {
    worker.postMessage('working fine');
}

डेमो: http://jsfiddle.net/8N6aR/


4

पश्चगामी अनुकूलता का समर्थन करने के कारण स्वीकृत उत्तर थोड़ा जटिल है, इसलिए मैं उसी चीज़ को पोस्ट करना चाहता था लेकिन सरलीकृत किया गया था। इसे अपने (आधुनिक) ब्राउज़र कंसोल में आज़माएँ:

const code = "console.log('Hello from web worker!')"
const blob = new Blob([code], {type: 'application/javascript'})
const worker = new Worker(URL.createObjectURL(blob))
// See the output in your console.


2

अच्छा जवाब - मैं आज एक ऐसी ही समस्या पर काम कर रहा हूं जब वे उपलब्ध नहीं होने पर फालबैक क्षमताओं के साथ वेब वर्कर्स बनाने की कोशिश कर रहे हैं (यानी मुख्य थ्रेड में वर्कर स्क्रिप्ट चलाएं)। चूंकि यह धागा विषय से संबंधित है, मैंने सोचा कि मैं यहां अपना समाधान प्रदान करूंगा:

    <script type="javascript/worker">
        //WORKER FUNCTIONS
        self.onmessage = function(event) {
            postMessage('Hello, ' + event.data.name + '!');
        }
    </script>

    <script type="text/javascript">

        function inlineWorker(parts, params, callback) {

            var URL = (window.URL || window.webkitURL);

            if (!URL && window.Worker) {

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

                worker.onmessage = function(event) {
                  callback(event.data);
                };

                worker.postMessage(params);

            } else {

                var postMessage = function(result) {
                  callback(result);
                };

                var self = {}; //'self' in scope of inlineWorker. 
                eval(parts); //Converts self.onmessage function string to function on self via nearest scope (previous line) - please email chrisgwgreen.site@gmail.com if this could be tidier.
                self.onmessage({ 
                    data: params 
                });
            }
        }

        inlineWorker(
            document.querySelector('[type="javascript/worker"]').textContent, 
            {
                name: 'Chaps!!'
            },
            function(result) {
                document.body.innerHTML = result;
            }
        );

    </script>
</body>


1

आपके उपयोग के मामले के आधार पर आप कुछ का उपयोग कर सकते हैं

कार्य .js सभी कोर पर चलाने के लिए सीपीयू गहन कोड प्राप्त करने के लिए सरलीकृत इंटरफ़ेस (नोड। जेएस, और वेब)

एक उदाहरण होगा

// turn blocking pure function into a worker task
const functionFromPostRequest = task.wrap('function (exampleArgument) {}');

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

1

@ Chanu_Sukarno के कोड पर विस्तार करते हुए, आप बस इस फ़ंक्शन में एक कार्यकर्ता फ़ंक्शन (या स्ट्रिंग) में पास कर सकते हैं और यह एक वेब कार्यकर्ता के अंदर निष्पादित करेगा:

async function doWorkerTask(workerFunction, input, buffers) {
  // Create worker
  let fnString = '(' + workerFunction.toString().replace('"use strict";', '') + ')();';
  let workerBlob = new Blob([fnString]);
  let workerBlobURL = window.URL.createObjectURL(workerBlob, { type: 'application/javascript; charset=utf-8' });
  let worker = new Worker(workerBlobURL);

  // Run worker
  return await new Promise(function(resolve, reject) {
    worker.onmessage = function(e) { resolve(e.data); };
    worker.postMessage(input, buffers);
  });
}

इसका उपयोग कैसे करें इसका एक उदाहरण यहां दिया गया है:

function myTask() {
  self.onmessage = function(e) {
    // do stuff with `e.data`, then:
    self.postMessage("my response");
    self.close();
  }
}
let output = await doWorkerTask(myTask, input, inputBuffers);
// now you can do something with `output` (which will be equal to "my response")


में NodeJS , doWorkerTaskइस तरह दिखता है:

async function doWorkerTask(workerFunction, input, buffers) {
  let Worker = require('webworker-threads').Worker;
  let worker = new Worker(workerFunction);

  // Run worker
  return await new Promise(function(resolve, reject) {
    worker.onmessage = function(e) { resolve(e.data); };
    worker.postMessage(input, buffers);
  });
}

-1

आप ऑब्जेक्ट -डेटा से वास्तविक-डेटा प्राप्त कर सकते हैं और केवल या responseTypeतो बदलकर बूँद नहीं "text"कर सकते हैं "arraybuffer"

यहां बैक टू बैक या text/javascriptटू में रूपांतरण है ।blobobjectURLblobtext/javascript

यदि आप सोच रहे हैं, तो मैं इसका उपयोग कर रहा हूँ, बिना किसी बाहरी फ़ाइलों के साथ एक वेब-वर्कर उत्पन्न करने के लिए, जिसका
उपयोग आप बाइनरी कंटेंट को वापस करने के लिए कर सकते हैं, YouTube वीडियो के लिए?) (<वीडियो> टैग संसाधन विशेषता से)

var blob = new Blob(['self.onmessage=function(e){postMessage(e)}'],{type: 'text/javascript'});   //->console: (object)   Blob {size: 42, type: "text/javascript", slice: function}

var obju = URL.createObjectURL(js_blob); //->console:  "blob:http%3A//stackoverflow.com/02e79c2b-025a-4293-be0f-f121dd57ccf7"

var xhr = new XMLHttpRequest();
xhr.open('GET', 'blob:http%3A//stackoverflow.com/02e79c2b-025a-4293-be0f-f121dd57ccf7', true);
xhr.responseType = 'text'; /* or "blob" */
xhr.onreadystatechange = function(){
  if(xhr.DONE !== xhr.readyState) return;

  console.log(xhr.response);
}
xhr.send();

/*
  responseType "blob" ->console: (object)   Blob {size: 42, type: "text/javascript", slice: function}
  responseType "text" ->console: (text)     'self.onmessage=function(e){postMessage(e)}'
*/

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.