6

मैं एक वेब ऐप बना रहा हूं जो मल्टीपार्ट अपलोड का उपयोग करके अमेज़ॅन एस 3 में बड़ी फाइलें अपलोड करने के लिए इवापोरेटजेएस का उपयोग करता है। मैंने एक मुद्दा देखा जहां हर बार एक नया हिस्सा शुरू किया गया था, ब्राउज़र ~ 2 सेकंड के लिए स्थिर हो जाएगा। मैं चाहता हूं कि उपयोगकर्ता प्रगति पर होने पर मेरे ऐप का उपयोग जारी रखने में सक्षम हो, और यह ठंडा करने से यह एक बुरा अनुभव बन जाता है।क्रोम में वर्कर अवरुद्ध यूआई थ्रेड

मैंने क्रोम की टाइमलाइन का उपयोग यह देखने के लिए किया कि यह क्या कारण था और यह पाया कि यह स्पार्कएमडी 5 की हैशिंग थी। तो मैंने पूरी अपलोड प्रक्रिया को एक वर्कर में स्थानांतरित कर दिया है, जिसे मैंने सोचा था कि इस मुद्दे को ठीक करेगा।

वैसे समस्या अब एज और फ़ायरफ़ॉक्स में तय की गई है, लेकिन क्रोम अभी भी एक ही समस्या है। Timeline

आप देख सकते हैं, फ्रीज़ के दौरान मेरी मुख्य थ्रेड मूल रूप से कुछ भी नहीं जावास्क्रिप्ट का < 8ms उस समय के दौरान चल रहे के साथ कर रही है,:

यहाँ मेरी समय का एक स्क्रीनशॉट है। मेरे काम को मेरे वर्कर थ्रेड में हो रहा है, और यहां तक ​​कि यह केवल ~ 600ms या उसके लिए चल रहा है, न कि 1386ms जो मेरा फ्रेम लेता है।

मुझे सच में यकीन नहीं है कि समस्या का कारण क्या है, क्या ऐसे श्रमिकों के साथ कोई गठिया है जिन्हें मुझे अवगत होना चाहिए?

var window = self; // For Worker-unaware scripts 

// Shim to make Evaporate work in a Worker 
var document = { 
    createElement: function() { 
     var href = undefined; 

     var elm = { 
      set href(url) { 
       var obj = new URL(url); 
       elm.protocol = obj.protocol; 
       elm.hostname = obj.hostname; 
       elm.pathname = obj.pathname; 
       elm.port = obj.port; 
       elm.search = obj.search; 
       elm.hash = obj.hash; 
       elm.host = obj.host; 
       href = url; 
      }, 
      get href() { 
       return href; 
      }, 
      protocol: undefined, 
      hostname: undefined, 
      pathname: undefined, 
      port: undefined, 
      search: undefined, 
      hash: undefined, 
      host: undefined 
     }; 

     return elm; 
    } 
}; 

importScripts("/lib/sha256/sha256.min.js"); 
importScripts("/lib/spark-md5/spark-md5.min.js"); 
importScripts("/lib/url-parse/url-parse.js"); 
importScripts("/lib/xmldom/xmldom.js"); 
importScripts("/lib/evaporate/evaporate.js"); 

DOMParser = self.xmldom.DOMParser; 

var defaultConfig = { 
    computeContentMd5: true, 
    cryptoMd5Method: function (data) { return btoa(SparkMD5.ArrayBuffer.hash(data, true)); }, 
    cryptoHexEncodedHash256: sha256, 
    awsSignatureVersion: "4", 
    awsRegion: undefined, 
    aws_url: "https://s3-ap-southeast-2.amazonaws.com", 
    aws_key: undefined, 
    customAuthMethod: function(signParams, signHeaders, stringToSign, timestamp, awsRequest) { 
     return new Promise(function(resolve, reject) { 
      var signingRequestId = currentSigningRequestId++; 

      postMessage(["signingRequest", signingRequestId, signParams.videoId, timestamp, awsRequest.signer.canonicalRequest()]); 
      queuedSigningRequests[signingRequestId] = function(signature) { 
       queuedSigningRequests[signingRequestId] = undefined; 
       if(signature) { 
        resolve(signature); 
       } else { 
        reject(); 
       } 
      } 
     }); 
    }, 
    //logging: false, 
    bucket: undefined, 
    allowS3ExistenceOptimization: false, 
    maxConcurrentParts: 5 
} 

var currentSigningRequestId = 0; 
var queuedSigningRequests = []; 

var e = undefined; 
var filekey = undefined; 
onmessage = function(e) { 
    var messageType = e.data[0]; 
    switch(messageType) { 
     case "init": 
      var globalConfig = {}; 
      for(var k in defaultConfig) { 
       globalConfig[k] = defaultConfig[k]; 
      } 
      for(var k in e.data[1]) { 
       globalConfig[k] = e.data[1][k]; 
      } 

      var uploadConfig = e.data[2]; 

      Evaporate.create(globalConfig).then(function(evaporate) { 
       var e = evaporate; 

       filekey = globalConfig.bucket + "/" + uploadConfig.name; 

       uploadConfig.progress = function(p, stats) { 
        postMessage(["progress", p, stats]); 
       }; 

       uploadConfig.complete = function(xhr, awsObjectKey, stats) { 
        postMessage(["complete", xhr, awsObjectKey, stats]); 
       } 

       uploadConfig.info = function(msg) { 
        postMessage(["info", msg]); 
       } 

       uploadConfig.warn = function(msg) { 
        postMessage(["warn", msg]); 
       } 

       uploadConfig.error = function(msg) { 
        postMessage(["error", msg]); 
       } 

       e.add(uploadConfig); 
      }); 
      break; 

     case "pause": 
      e.pause(filekey); 
      break; 

     case "resume": 
      e.resume(filekey); 
      break; 

     case "cancel": 
      e.cancel(filekey); 
      break; 

     case "signature": 
      var signingRequestId = e.data[1]; 
      var signature = e.data[2]; 
      queuedSigningRequests[signingRequestId](signature); 
      break; 
    } 
} 

ध्यान दें कि यह बुला धागे पर निर्भर करता है एडब्ल्यूएस सार्वजनिक कुंजी, एडब्ल्यूएस बाल्टी नाम और एडब्ल्यूएस क्षेत्र, एडब्ल्यूएस वस्तु कुंजी और इनपुट फ़ाइल वस्तु के साथ यह प्रदान करने के लिए:

यहाँ मेरी वर्कर के लिए कोड है , जो सभी 'init' संदेश में प्रदान किए जाते हैं। जब इसे किसी हस्ताक्षरित हस्ताक्षर की आवश्यकता होती है, तो यह पैरेंट थ्रेड को 'signRequest' संदेश भेजता है, जो कि मेरे एपीआई के हस्ताक्षर समापन बिंदु से प्राप्त होने के बाद 'हस्ताक्षर' संदेश में हस्ताक्षर प्रदान करने की अपेक्षा की जाती है।

+0

क्या यह मदद करता है? https://github.com/TTLabs/EvaporateJS/issues/257 – user650881

+0

वास्तव में नहीं।मुझे EvaporateJS के ओवरहेड के बारे में पता है और मैं इसका उपयोग कर प्रदर्शन समस्याओं का सामना कर रहा था, यही वजह है कि मैंने वर्कर थ्रेड का उपयोग शुरू किया। मेरा सवाल यह है कि यूआई थ्रेड अभी भी ठंडा है, भले ही सभी काम एक कर्मचारी में हो रहा हो। –

+0

जिज्ञासा से, क्या आपने कभी इसे हल किया है? – tony19

उत्तर

3

मैं एक बहुत अच्छा उदाहरण नहीं दे सकता या विश्लेषण कर सकता हूं कि आप केवल वर्कर कोड के साथ क्या कर रहे हैं, लेकिन मुझे दृढ़ता से संदेह है कि इस मुद्दे को मुख्य धागे पर या तो कुछ अप्रत्याशित रूप से खंड के पढ़ने के साथ करना है प्रसंस्करण कि आप मुख्य धागे पर खंड पर कर रहे हैं। हो सकता है कि मुख्य थ्रेड कोड पोस्ट करें जो श्रमिक को postMessage पर कॉल करता है?

अगर मैं अभी इसे डिबग कर रहा था, तो मैं आपके FileReader संचालन को वर्कर में ले जाने का प्रयास करूंगा। यदि आप वर्क अवरुद्ध करते समय वर्कर अवरुद्ध नहीं करते हैं, तो आप FileReaderSync का भी उपयोग कर सकते हैं।

पोस्ट-टिप्पणियां अद्यतन

presigned यूआरएल फ़ाइल सामग्री + मेटाडाटा + एक महत्वपूर्ण hashing की आवश्यकता होती है पैदा करता है? हैशिंग फ़ाइल सामग्री खंड के आकार में ओ (एन) ले जा रही है और यह संभव है, यदि हैश पहला ऑपरेशन है जो Blob से पढ़ता है, तो फ़ाइल सामग्री की लोडिंग को तब तक स्थगित कर दिया जा सकता है जब तक कि हैशिंग शुरू नहीं हो जाती। जब तक आप मुख्य धागे में साइन इन रखने के लिए बाध्य नहीं होते हैं (आप मुख्य सामग्री वाले कार्यकर्ता पर भरोसा नहीं करते हैं?) जो कार्यकर्ता को लाने के लिए एक और अच्छी बात होगी।

तो कार्यकर्ता में हस्ताक्षर किए जाने चलती बहुत ज्यादा है, तो आप कार्यकर्ता Blob मजबूर करने के लिए कुछ है पढ़ने के लिए है और/या ArrayBuffer (या Uint8Array या क्या आपके पास) फ़ाइल सामग्री के पीछे मुख्य करने के लिए दे सकते हैं हस्ताक्षर के लिए धागा; यह सुनिश्चित करेगा कि खंड को पढ़ना मुख्य धागे पर नहीं होता है।

+0

मेरे पास अभी इस कोड तक पहुंच नहीं है (और मेरे बकाया होने के बाद तक इसे तब तक एक्सेस नहीं होगा) इसलिए दुख की बात है कि मैं मुख्य थ्रेड कोड पोस्ट नहीं कर सकता। हालांकि यह कैसे काम करता है इसके बारे में एक सिंहावलोकन प्रदान करने के लिए मैं अपनी पूरी कोशिश करूंगा। सबसे पहले मैं यह स्पष्ट करना चाहता हूं कि मेरे फ़ाइल रीडर ऑपरेशन वास्तव में कार्यकर्ता के भीतर हो रहे हैं। आप मेरे द्वारा पोस्ट किए गए कोड में कॉल नहीं देख सकते हैं क्योंकि EvaporateJS फ़ाइल पढ़ने को संभालता है, लेकिन मुख्य धागे पर मैं किसी भी फ़ाइल रीडर फ़ंक्शंस का उपयोग नहीं करता हूं या यहां तक ​​कि EvaporateJS लोड भी नहीं होता है। –

+0

यहां मुख्य थ्रेड ऑपरेशंस हैं: (1) उपयोगकर्ता इनपुट [type = file] तत्व का उपयोग करके अपनी फ़ाइल का चयन करता है। मुख्य धागा फ़ाइल नाम को पकड़ता है और फ़ाइल को अपलोड करने के लिए यह पता लगाने के लिए मेरे एपीआई से अनुरोध करता है। मुख्य धागा तो वर्कर को 'init' संदेश भेजने के लिए पोस्ट मैसेज का उपयोग करता है। (2) कर्मचारी अपलोड प्रक्रिया शुरू करता है। जब भी इसे एडब्ल्यूएस निर्धारित यूआरएल की आवश्यकता होती है, तो यह मुख्य थ्रेड में 'signRequest' नामक एक पोस्ट मैसेज भेजता है। (3) हस्ताक्षर अनुरोध के साथ मुख्य धागा असीमित रूप से मेरे एपीआई को कॉल करता है। एक बार हस्ताक्षर होने के बाद, यह एक पोस्ट मैसेज भेजता है जिसे श्रमिक को 'हस्ताक्षर' कहा जाता है। –

+0

(4) प्रगति अद्यतन होने पर कार्यकर्ता मुख्य धागे पर 'प्रगति' संदेश भेजता है। (5) मुख्य धागा फिर नई प्रगति के साथ अपने यूआई को अद्यतन करने के लिए एक कोणीय पाचन कहते हैं। (6) अपलोड पूरा होने पर श्रमिक 'पूर्ण' संदेश भेजता है। –

संबंधित मुद्दे