2016-02-29 7 views
37

मैं fetch का उपयोग कर एक अपलोड प्रगति संकेतक को लागू करने के दस्तावेज़ीकरण या उदाहरण खोजने के लिए संघर्ष कर रहा हूं।लाने के लिए प्रगति संकेतक अपलोड करें?

This is the only reference I've found so far, जिसमें कहा गया है:

प्रगति की घटनाओं में एक उच्च स्तरीय विशेषता यह है कि अब के लिए लाने के आने नहीं होगा। आप Content-Length शीर्षलेख देखकर और प्राप्त बाइट्स की निगरानी के लिए पास-थ्रू स्ट्रीम का उपयोग कर अपना स्वयं का निर्माण कर सकते हैं।

इसका मतलब है कि आप स्पष्ट रूप से Content-Length के बिना प्रतिक्रियाओं को स्पष्ट रूप से संभाल सकते हैं। और निश्चित रूप से, भले ही Content-Length यहां एक झूठ हो सकती है। धाराओं के साथ आप इन झूठों को संभाल सकते हैं हालांकि आप चाहते हैं।

मैं "बाइट्स की निगरानी करने के लिए पास-थ्रू स्ट्रीम" कैसे लिखूं? यदि यह किसी प्रकार का अंतर बनाता है, तो मैं ब्राउज़र से छवि अपलोड करने के लिए इसे Cloudinary पर करने की कोशिश कर रहा हूं।

नोट: मैं, Cloudinary JS library में दिलचस्पी नहीं है के रूप में यह jQuery पर निर्भर करता है और मेरे ऐप नहीं है। मुझे मूल जावास्क्रिप्ट और गिथब के fetch पॉलीफिल के साथ ऐसा करने के लिए आवश्यक स्ट्रीम प्रोसेसिंग में दिलचस्पी है।


https://fetch.spec.whatwg.org/#fetch-api

+3

@Magix [लाए जाने छोड़ रहा: अगली पीढ़ी # 447] देखें। (Https: // GitHub।com/whatwg/fetch/issues/447) – guest271314

उत्तर

23

स्ट्रीम वेब प्लेटफ़ॉर्म (https://jakearchibald.com/2016/streams-ftw/) में उतरने शुरू हो रहे हैं लेकिन यह अभी भी शुरुआती दिनों में है।

जल्द ही आप अनुरोध के निकाय के रूप में एक धारा प्रदान करने में सक्षम होंगे, लेकिन खुला प्रश्न यह है कि उस स्ट्रीम की खपत अपलोड किए गए बाइट से संबंधित है या नहीं।

विशेष रीडायरेक्ट के परिणामस्वरूप डेटा को नए स्थान पर पुनः प्रेषित किया जा सकता है, लेकिन स्ट्रीम "पुनरारंभ" नहीं कर सकती हैं। हम शरीर को कॉलबैक में बदलकर इसे ठीक कर सकते हैं जिसे कई बार कहा जा सकता है, लेकिन हमें यह सुनिश्चित करने की ज़रूरत है कि रीडायरेक्ट की संख्या को उजागर करना एक सुरक्षा रिसाव नहीं है, क्योंकि यह प्लेटफार्म जेएस पर पहली बार होगा इसका पता लगाएं।

कुछ सवाल कर रहे हैं कि क्या अपलोड की गई बाइट्स को स्ट्रीम खपत को जोड़ने का अर्थ भी है।

लंबी कहानी लघु: यह अभी तक संभव नहीं है, लेकिन भविष्य में इसे या तो स्ट्रीम द्वारा संभाला जाएगा, या किसी प्रकार का उच्च स्तरीय कॉलबैक fetch() में पारित किया जाएगा।

+4

बहुत बुरा। इसे अभी स्वीकार कर रहा है, लेकिन जब यह वास्तविकता बन जाता है, तो मुझे उम्मीद है कि कोई और एक अद्यतन समाधान पोस्ट करेगा! :) – neezer

+0

@ jaffa-the-cake कोई खबर? – mu3

+1

अद्यतन - धाराओं का उपयोग करके fetch API के साथ प्रगति दिखा रहा है - https://twitter.com/umaar/status/917789464658890753/photo/1 –

5

मैं यह संभव है नहीं लगता। मसौदा कहता है:

यह वर्तमान में [एक्सएचआर की तुलना में ] की कमी है जब यह प्रगति का अनुरोध करने के लिए आता


(वर्ष जवाब):
में पहला उदाहरण Fetch API chapter इस बारे में कुछ अंतर्दृष्टि देता है कि कैसे:

आप उत्तरोत्तर शरीर डेटा प्राप्त करना चाहते हैं:

function consume(reader) { 
    var total = 0 
    return new Promise((resolve, reject) => { 
    function pump() { 
     reader.read().then(({done, value}) => { 
     if (done) { 
      resolve() 
      return 
     } 
     total += value.byteLength 
     log(`received ${value.byteLength} bytes (${total} bytes in total)`) 
     pump() 
     }).catch(reject) 
    } 
    pump() 
    }) 
} 

fetch("/music/pk/altes-kamuffel.flac") 
    .then(res => consume(res.body.getReader())) 
    .then(() => log("consumed the entire body without keeping the whole thing in memory!")) 
    .catch(e => log("something went wrong: " + e)) 

अलावा Promise constructor antipattern के उनके उपयोग से, आप देख सकते हैं कि response.body एक स्ट्रीम जिसमें से आप एक रीडर का उपयोग कर बाइट द्वारा बाइट पढ़ सकते है, और आप किसी ईवेंट को आग लगाना या जो भी आपको पसंद है (उदाहरण के लिए उनमें से प्रत्येक के लिए प्रगति लॉग करें)।

हालांकि, Streams spec काफी समाप्त नहीं हुआ प्रतीत होता है, और मुझे नहीं पता कि यह किसी भी fetch कार्यान्वयन में पहले से ही काम करता है या नहीं।

+5

यदि मैं उस उदाहरण को सही तरीके से पढ़ता हूं, हालांकि, यह ** डाउनलोड करने के लिए ** ** fetch' के माध्यम से एक फ़ाइल डाउनलोड करेगा। मुझे ** एक फ़ाइल ** अपलोड करने के लिए प्रगति संकेतकों में दिलचस्पी है। – neezer

+0

ओह, यह उद्धरण * प्राप्त * बाइट्स के बारे में बात करता है, जो मुझे भ्रमित करता है। – Bergi

+0

@ बर्गि नोट, 'वादा' कन्स्ट्रक्टर आवश्यक नहीं है। 'Response.body.getReader()' एक 'वादा' देता है। देखें [बड़े आकार के जेसन डाउनलोड करते समय अनकॉल्ड रेंज एरर को कैसे हल करें] (http://stackoverflow.com/questions/39959467/how-to-solve-uncaught-rangeerror-when-download-large-size-json) – guest271314

2

एक संभावित समाधान, new Request() निर्माता का उपयोग किया जाएगा तो जाँच Request.bodyUsedBoolean विशेषता

bodyUsed विशेषता के गेटर अगर disturbed सच लौटना चाहिए, और झूठी अन्यथा।

निर्धारित करने के लिए करता है, तो धारा distributed

है Body mixin को लागू करने वाली वस्तु होने की disturbed अगर body में गैर-शून्य है और इसके streamdisturbed है कहा जाता है।

वापसी fetch()Promise.then() के भीतर से एक ReadableStream की .read() कॉल पुनरावर्ती जब Request.bodyUsedtrue के बराबर है श्रृंखलित।

नोट, दृष्टिकोण Request.body के बाइट्स को नहीं पढ़ता है क्योंकि बाइट्स एंडपॉइंट पर स्ट्रीम किए जाते हैं। साथ ही, ब्राउज़र पर पूरी तरह से प्रतिक्रिया लौटने से पहले अपलोड पूरी तरह से पूरा हो सकता है।

const [input, progress, label] = [ 
    document.querySelector("input") 
    , document.querySelector("progress") 
    , document.querySelector("label") 
]; 

const url = "/path/to/server/"; 

input.onmousedown =() => { 
    label.innerHTML = ""; 
    progress.value = "0" 
}; 

input.onchange = (event) => { 

    const file = event.target.files[0]; 
    const filename = file.name; 
    progress.max = file.size; 

    const request = new Request(url, { 
    method: "POST", 
    body: file, 
    cache: "no-store" 
    }); 

    const upload = settings => fetch(settings); 

    const uploadProgress = new ReadableStream({ 
    start(controller) { 
     console.log("starting upload, request.bodyUsed:", request.bodyUsed); 
     controller.enqueue(request.bodyUsed); 
    }, 
    pull(controller) { 
     if (request.bodyUsed) { 
     controller.close(); 
     } 
     controller.enqueue(request.bodyUsed); 
     console.log("pull, request.bodyUsed:", request.bodyUsed); 
    }, 
    cancel(reason) { 
     console.log(reason); 
    } 
    }); 

    const [fileUpload, reader] = [ 
    upload(request) 
    .catch(e => { 
     reader.cancel(); 
     throw e 
    }) 
    , uploadProgress.getReader() 
    ]; 

    const processUploadRequest = ({value, done}) => { 
    if (value || done) { 
     console.log("upload complete, request.bodyUsed:", request.bodyUsed); 
     // set `progress.value` to `progress.max` here 
     // if not awaiting server response 
     // progress.value = progress.max; 
     return reader.closed.then(() => fileUpload); 
    } 
    console.log("upload progress:", value); 
    progress.value = +progress.value + 1; 
    return reader.read().then(result => processUploadRequest(result)); 
    }; 

    reader.read().then(({value, done}) => processUploadRequest({value,done})) 
    .then(response => response.text()) 
    .then(text => { 
    console.log("response:", text); 
    progress.value = progress.max; 
    input.value = ""; 
    }) 
    .catch(err => console.log("upload error:", err)); 

} 
3

के बाद से जवाब में से कोई भी समस्या का समाधान।

बस कार्यान्वयन के लिए, आप अपलोड की गति with some small initial chunk of known size का पता लगा सकते हैं और अपलोड समय की गणना सामग्री-लंबाई/अपलोड-गति के साथ की जा सकती है। आप अनुमान के रूप में इस समय का उपयोग कर सकते हैं।

+1

जब हम रीयलटाइम समाधान की प्रतीक्षा करते हैं तो उपयोग करने के लिए बहुत चालाक, अच्छी चाल :) – Magix

0

मुख्य भाग ReadableStreamobj_response .body ≫।

नमूना:

let parse=_/*result*/=>{ 
    console.log(_) 
    //... 
    return /*cont?*/_.value?true:false 
} 

fetch(''). 
then(_=>(a/*!*/=_.body.getReader(), b/*!*/=z=>a.read().then(parse).then(_=>(_?b:z=>z)()), b())) 

आप एक विशाल पेज जैसे https://html.spec.whatwg.org/ और https://html.spec.whatwg.org/print.pdf पर इसे चलाने परीक्षण कर सकते हैं। CtrlShiftJ और में कोड को लोड

(क्रोम पर परीक्षण किया गया।)

0
const req = await fetch('./foo.json'); 
const total = Number(req.headers.get('content-length')); 
let loaded = 0; 
for await(const {length} of req.body.getReader()) { 
    loaded = += length; 
    const progress = ((loaded/total) * 100).toFixed(2); // toFixed(2) means two digits after floating point 
    console.log(`${progress}%`); // or yourDiv.textContent = `${progress}%`; 
} 
+0

यह कभी भी 'ReadableStreamDefaultReader' के रूप में काम नहीं करेगा' बाइट लम्बाई 'संपत्ति नहीं है। – silicakes

+0

मैं पूरे जवाब के लिए बेंजामिन ग्रुनेबाम को श्रेय देना चाहता हूं। क्योंकि मैंने इसे अपने व्याख्यान से सीखा। –

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