কর্মীদের জন্য সিঙ্ক্রোনাস ফাইলসিস্টেম API

ভূমিকা

HTML5 ফাইলসিস্টেম এপিআই এবং ওয়েব ওয়ার্কাররা তাদের নিজস্ব ক্ষেত্রে ব্যাপকভাবে শক্তিশালী। ফাইলসিস্টেম এপিআই অবশেষে ওয়েব অ্যাপ্লিকেশনগুলিতে হায়ারার্কিক্যাল স্টোরেজ এবং ফাইল I/O নিয়ে আসে এবং শ্রমিকরা জাভাস্ক্রিপ্টে সত্যিকারের অ্যাসিঙ্ক্রোনাস 'মাল্টি-থ্রেডিং' নিয়ে আসে। যাইহোক, যখন আপনি এই APIগুলি একসাথে ব্যবহার করেন, আপনি কিছু সত্যিকারের আকর্ষণীয় অ্যাপ তৈরি করতে পারেন।

এই টিউটোরিয়ালটি একটি ওয়েব ওয়ার্কারের ভিতরে HTML5 ফাইলসিস্টেম ব্যবহার করার জন্য একটি গাইড এবং কোড উদাহরণ প্রদান করে। এটি উভয় API-এর কাজের জ্ঞান অনুমান করে। আপনি যদি এই API গুলি সম্পর্কে আরও জানতে আগ্রহী না হন বা আপনি যদি এই APIগুলি সম্পর্কে আরও জানার জন্য প্রস্তুত না হন তবে দুটি দুর্দান্ত টিউটোরিয়াল পড়ুন যা বেসিকগুলি নিয়ে আলোচনা করে: ফাইলসিস্টেম এপিআই এবং ওয়েব ওয়ার্কার্সের বেসিকগুলি অন্বেষণ করা৷

সিঙ্ক্রোনাস বনাম অ্যাসিঙ্ক্রোনাস API

অ্যাসিঙ্ক্রোনাস জাভাস্ক্রিপ্ট API ব্যবহার করা কঠিন হতে পারে। তারা বড়. তারা জটিল। তবে সবচেয়ে হতাশার বিষয় হল যে তারা জিনিসগুলিকে ভুল হওয়ার জন্য প্রচুর সুযোগ দেয়। শেষ যে জিনিসটি আপনি মোকাবেলা করতে চান তা হল একটি জটিল অ্যাসিঙ্ক্রোনাস এপিআই (ফাইলসিস্টেম) একটি ইতিমধ্যেই অ্যাসিঙ্ক্রোনাস বিশ্বে (শ্রমিকদের) স্তর স্থাপন করা! ভাল খবর হল যে FileSystem API ওয়েব ওয়ার্কারদের ব্যথা কমাতে একটি সিঙ্ক্রোনাস সংস্করণ সংজ্ঞায়িত করে।

বেশিরভাগ অংশে, সিঙ্ক্রোনাস API এর অ্যাসিঙ্ক্রোনাস কাজিনের মতোই। পদ্ধতি, বৈশিষ্ট্য, বৈশিষ্ট্য, এবং কার্যকারিতা পরিচিত হবে. প্রধান বিচ্যুতি হল:

  • সিঙ্ক্রোনাস এপিআই শুধুমাত্র একটি ওয়েব ওয়ার্কার প্রসঙ্গে ব্যবহার করা যেতে পারে, যেখানে অ্যাসিঙ্ক্রোনাস এপিআই ওয়ার্কারের মধ্যে এবং বাইরে ব্যবহার করা যেতে পারে।
  • কলব্যাক আউট. API পদ্ধতি এখন মান প্রদান করে।
  • উইন্ডো অবজেক্টের গ্লোবাল মেথড ( requestFileSystem() এবং resolveLocalFileSystemURL() ) requestFileSystemSync() এবং resolveLocalFileSystemSyncURL() হয়ে যায়।

এই ব্যতিক্রমগুলি ছাড়াও, APIগুলি একই। ঠিক আছে, আমরা যেতে চাই!

একটি ফাইল সিস্টেম অনুরোধ করা হচ্ছে

একটি ওয়েব অ্যাপ্লিকেশান একটি ওয়েব ওয়ার্কারের মধ্যে থেকে একটি LocalFileSystemSync অবজেক্টের অনুরোধ করে সিঙ্ক্রোনাস ফাইল সিস্টেমে অ্যাক্সেস পায়৷ requestFileSystemSync() কর্মীর বিশ্বব্যাপী সুযোগের সংস্পর্শে এসেছে:

var fs = requestFileSystemSync(TEMPORARY, 1024*1024 /*1MB*/);

এখন নতুন রিটার্ন মান লক্ষ্য করুন যে আমরা সিঙ্ক্রোনাস API ব্যবহার করছি সেইসাথে সাফল্য এবং ত্রুটি কলব্যাকের অনুপস্থিতি।

সাধারণ ফাইলসিস্টেম API-এর মতো, পদ্ধতিগুলি এই মুহূর্তে উপসর্গযুক্ত:

self.requestFileSystemSync = self.webkitRequestFileSystemSync ||
                                 self.requestFileSystemSync;

কোটা নিয়ে কাজ করা

বর্তমানে, কর্মী প্রসঙ্গে PERSISTENT কোটার অনুরোধ করা সম্ভব নয়। আমি শ্রমিকদের বাইরে কোটা সংক্রান্ত বিষয়গুলো যত্ন নেওয়ার পরামর্শ দিচ্ছি। প্রক্রিয়াটি এইরকম দেখতে পারে:

  1. worker.js: যেকোন ফাইলসিস্টেম এপিআই কোডকে try/catch করে মুড়ে দিন যাতে কোনো QUOTA_EXCEED_ERR ত্রুটি ধরা পড়ে।
  2. worker.js: যদি আপনি একটি QUOTA_EXCEED_ERR ধরতে পারেন, তাহলে মূল অ্যাপে একটি postMessage('get me more quota') পাঠান।
  3. প্রধান অ্যাপ: #2 প্রাপ্ত হলে window.webkitStorageInfo.requestQuota() নাচের মধ্য দিয়ে যান।
  4. প্রধান অ্যাপ: ব্যবহারকারী আরও কোটা মঞ্জুর করার পরে, অতিরিক্ত স্টোরেজ স্পেস সম্পর্কে জানানোর জন্য কর্মীকে postMessage('resume writes') পাঠান।

এটি একটি মোটামুটি জড়িত সমাধান, কিন্তু এটি কাজ করা উচিত। FileSystem API-এর সাথে PERSISTENT স্টোরেজ ব্যবহার করার বিষয়ে আরও তথ্যের জন্য অনুরোধ কোটা দেখুন।

ফাইল এবং ডিরেক্টরি নিয়ে কাজ করা

getFile() এবং getDirectory() এর সিঙ্ক্রোনাস সংস্করণ যথাক্রমে একটি FileEntrySync এবং DirectoryEntrySync প্রদান করে।

উদাহরণস্বরূপ, নিম্নলিখিত কোডটি রুট ডিরেক্টরিতে "log.txt" নামে একটি খালি ফাইল তৈরি করে।

var fileEntry = fs.root.getFile('log.txt', {create: true});

নিম্নলিখিতটি রুট ফোল্ডারে একটি নতুন ডিরেক্টরি তৈরি করে।

var dirEntry = fs.root.getDirectory('mydir', {create: true});

হ্যান্ডলিং ত্রুটি

যদি আপনাকে কখনই ওয়েব ওয়ার্কার কোড ডিবাগ করতে না হয়, আমি আপনাকে হিংসা করি! কি ভুল হচ্ছে তা বের করা সত্যিকারের কষ্ট হতে পারে।

সিঙ্ক্রোনাস বিশ্বে ত্রুটি কলব্যাকের অভাব সমস্যাগুলির সাথে মোকাবিলা করা উচিত তার চেয়ে জটিল করে তোলে। যদি আমরা ওয়েব ওয়ার্কার কোড ডিবাগ করার সাধারণ জটিলতা যোগ করি, তাহলে আপনি কিছুক্ষণের মধ্যেই হতাশ হবেন। একটি জিনিস যা জীবনকে সহজ করে তুলতে পারে তা হল আপনার সমস্ত প্রাসঙ্গিক কর্মী কোড একটি চেষ্টা/ক্যাচে মোড়ানো। তারপরে, যদি কোনো ত্রুটি দেখা দেয়, postMessage() ব্যবহার করে ত্রুটিটিকে মূল অ্যাপে ফরোয়ার্ড করুন:

function onError(e) {
    postMessage('ERROR: ' + e.toString());
}

try {
    // Error thrown if "log.txt" already exists.
    var fileEntry = fs.root.getFile('log.txt', {create: true, exclusive: true});
} catch (e) {
    onError(e);
}

Files, Blobs, এবং ArrayBuffers এর চারপাশে ক্ষণস্থায়ী

যখন ওয়েব ওয়ার্কাররা প্রথম দৃশ্যে আসে, তারা শুধুমাত্র postMessage() এ স্ট্রিং ডেটা পাঠানোর অনুমতি দেয়। পরে, ব্রাউজারগুলি সিরিয়ালাইজেবল ডেটা গ্রহণ করতে শুরু করে, যার অর্থ হল একটি JSON অবজেক্ট পাস করা সম্ভব। যদিও সম্প্রতি, Chrome এর মতো কিছু ব্রাউজার স্ট্রাকচার্ড ক্লোন অ্যালগরিদম ব্যবহার করে postMessage() মাধ্যমে পাস করার জন্য আরও জটিল ডেটা টাইপ গ্রহণ করে।

এই আসলে কি মানে? এর মানে হল যে প্রধান অ্যাপ এবং ওয়ার্কার থ্রেডের মধ্যে বাইনারি ডেটা পাস করা অনেক সহজ। কর্মীদের জন্য কাঠামোবদ্ধ ক্লোনিং সমর্থন করে এমন ব্রাউজারগুলি আপনাকে টাইপ করা অ্যারে, ArrayBuffer , File বা Blob শ্রমিকদের মধ্যে পাস করার অনুমতি দেয়। যদিও ডেটা এখনও একটি অনুলিপি, একটি File পাস করতে সক্ষম হওয়ার অর্থ হল প্রাক্তন পদ্ধতির তুলনায় একটি কর্মক্ষমতা সুবিধা, যার মধ্যে ফাইলটিকে postMessage() এ পাস করার আগে বেস64 করা জড়িত।

নিম্নলিখিত উদাহরণটি একজন ডেডিকেটেড ওয়ার্কারকে ফাইলগুলির একটি ব্যবহারকারী-নির্বাচিত তালিকা পাস করে। কর্মী কেবল ফাইল তালিকার মধ্য দিয়ে যায় (প্রত্যাবর্তন করা ডেটা আসলে একটি FileList দেখানোর জন্য সহজ) এবং মূল অ্যাপটি প্রতিটি ফাইলকে একটি ArrayBuffer হিসাবে পড়ে।

নমুনাটি ওয়েব ওয়ার্কারদের মৌলিক বিষয়গুলিতে বর্ণিত ইনলাইন ওয়েব ওয়ার্কার কৌশলের একটি উন্নত সংস্করণও ব্যবহার করে।

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="chrome=1">
    <title>Passing a FileList to a Worker</title>
    <script type="javascript/worker" id="fileListWorker">
    self.onmessage = function(e) {
    // TODO: do something interesting with the files.
    postMessage(e.data); // Pass through.
    };
    </script>
</head>
<body>
</body>

<input type="file" multiple>

<script>
document.querySelector('input[type="file"]').addEventListener('change', function(e) {
    var files = this.files;
    loadInlineWorker('#fileListWorker', function(worker) {

    // Setup handler to process messages from the worker.
    worker.onmessage = function(e) {

        // Read each file aysnc. as an array buffer.
        for (var i = 0, file; file = files[i]; ++i) {
        var reader = new FileReader();
        reader.onload = function(e) {
            console.log(this.result); // this.result is the read file as an ArrayBuffer.
        };
        reader.onerror = function(e) {
            console.log(e);
        };
        reader.readAsArrayBuffer(file);
        }

    };

    worker.postMessage(files);
    });
}, false);


function loadInlineWorker(selector, callback) {
    window.URL = window.URL || window.webkitURL || null;

    var script = document.querySelector(selector);
    if (script.type === 'javascript/worker') {
    var blob = new Blob([script.textContent]);
    callback(new Worker(window.URL.createObjectURL(blob));
    }
}
</script>
</html>

একজন কর্মী ফাইল পড়া

ওয়ার্কারে ফাইল পড়ার জন্য অ্যাসিঙ্ক্রোনাস FileReader API ব্যবহার করা সম্পূর্ণরূপে গ্রহণযোগ্য। যাইহোক, একটি ভাল উপায় আছে. কর্মীদের মধ্যে, একটি সিঙ্ক্রোনাস API ( FileReaderSync ) রয়েছে যা ফাইলগুলি পড়ার স্ট্রিমলাইন করে:

প্রধান অ্যাপ:

<!DOCTYPE html>
<html>
<head>
    <title>Using FileReaderSync Example</title>
    <style>
    #error { color: red; }
    </style>
</head>
<body>
<input type="file" multiple />
<output id="error"></output>
<script>
    var worker = new Worker('worker.js');

    worker.onmessage = function(e) {
    console.log(e.data); // e.data should be an array of ArrayBuffers.
    };

    worker.onerror = function(e) {
    document.querySelector('#error').textContent = [
        'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message].join('');
    };

    document.querySelector('input[type="file"]').addEventListener('change', function(e) {
    worker.postMessage(this.files);
    }, false);
</script>
</body>
</html>

worker.js

self.addEventListener('message', function(e) {
    var files = e.data;
    var buffers = [];

    // Read each file synchronously as an ArrayBuffer and
    // stash it in a global array to return to the main app.
    [].forEach.call(files, function(file) {
    var reader = new FileReaderSync();
    buffers.push(reader.readAsArrayBuffer(file));
    });

    postMessage(buffers);
}, false);

প্রত্যাশিত হিসাবে, সিঙ্ক্রোনাস FileReader সাথে কলব্যাক চলে গেছে। এটি ফাইল পড়ার সময় কলব্যাক নেস্টিংয়ের পরিমাণকে সহজ করে। পরিবর্তে, readAs* পদ্ধতিগুলি পঠিত ফাইলটি ফেরত দেয়।

উদাহরণ: সমস্ত এন্ট্রি আনা

কিছু ক্ষেত্রে, সিঙ্ক্রোনাস API নির্দিষ্ট কাজের জন্য অনেক বেশি পরিষ্কার। কম কলব্যাক সুন্দর এবং অবশ্যই জিনিসগুলিকে আরও পাঠযোগ্য করে তোলে। সিঙ্ক্রোনাস API-এর আসল খারাপ দিকটি শ্রমিকদের সীমাবদ্ধতা থেকে উদ্ভূত হয়।

নিরাপত্তার কারণে, কলিং অ্যাপ এবং ওয়েব ওয়ার্কার থ্রেডের মধ্যে ডেটা কখনই শেয়ার করা হয় না। যখন postMessage() কল করা হয় তখন ওয়ার্কারের কাছে এবং থেকে ডেটা সবসময় কপি করা হয়। ফলস্বরূপ, প্রতিটি ডেটা টাইপ পাস করা যায় না।

দুর্ভাগ্যবশত, FileEntrySync এবং DirectoryEntrySync বর্তমানে গৃহীত প্রকারের মধ্যে পড়ে না। তাহলে কিভাবে আপনি কলিং অ্যাপে এন্ট্রি ফিরে পেতে পারেন? সীমাবদ্ধতা এড়ানোর একটি উপায় হল ফাইল সিস্টেমের একটি তালিকা ফেরত দেওয়া: এন্ট্রির তালিকার পরিবর্তে ইউআরএলfilesystem: ইউআরএলগুলি কেবল স্ট্রিং, তাই এগুলি পাস করা খুব সহজ। উপরন্তু, সেগুলি resolveLocalFileSystemURL() ব্যবহার করে মূল অ্যাপের এন্ট্রিগুলিতে সমাধান করা যেতে পারে। এটি আপনাকে একটি FileEntrySync / DirectoryEntrySync অবজেক্টে ফিরিয়ে দেয়।

প্রধান অ্যাপ:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>Listing filesystem entries using the synchronous API</title>
</head>
<body>
<script>
    window.resolveLocalFileSystemURL = window.resolveLocalFileSystemURL ||
                                        window.webkitResolveLocalFileSystemURL;

    var worker = new Worker('worker.js');
    worker.onmessage = function(e) {
    var urls = e.data.entries;
    urls.forEach(function(url, i) {
        window.resolveLocalFileSystemURL(url, function(fileEntry) {
        console.log(fileEntry.name); // Print out file's name.
        });
    });
    };

    worker.postMessage({'cmd': 'list'});
</script>
</body>
</html>

worker.js

self.requestFileSystemSync = self.webkitRequestFileSystemSync ||
                                self.requestFileSystemSync;

var paths = []; // Global to hold the list of entry filesystem URLs.

function getAllEntries(dirReader) {
    var entries = dirReader.readEntries();

    for (var i = 0, entry; entry = entries[i]; ++i) {
    paths.push(entry.toURL()); // Stash this entry's filesystem: URL.

    // If this is a directory, we have more traversing to do.
    if (entry.isDirectory) {
        getAllEntries(entry.createReader());
    }
    }
}

function onError(e) {
    postMessage('ERROR: ' + e.toString()); // Forward the error to main app.
}

self.onmessage = function(e) {
    var data = e.data;

    // Ignore everything else except our 'list' command.
    if (!data.cmd || data.cmd != 'list') {
    return;
    }

    try {
    var fs = requestFileSystemSync(TEMPORARY, 1024*1024 /*1MB*/);

    getAllEntries(fs.root.createReader());

    self.postMessage({entries: paths});
    } catch (e) {
    onError(e);
    }
};

উদাহরণ: XHR2 ব্যবহার করে ফাইল ডাউনলোড করা

শ্রমিকদের জন্য একটি সাধারণ ব্যবহারের ক্ষেত্রে XHR2 ব্যবহার করে একগুচ্ছ ফাইল ডাউনলোড করা এবং সেই ফাইলগুলিকে HTML5 ফাইলসিস্টেমে লেখা। এটি একটি ওয়ার্কার থ্রেডের জন্য একটি নিখুঁত কাজ!

নিম্নলিখিত উদাহরণটি শুধুমাত্র একটি ফাইল নিয়ে আসে এবং লিখতে পারে, কিন্তু আপনি ফাইলগুলির একটি সেট ডাউনলোড করতে এটিকে প্রসারিত করতে পারেন৷

প্রধান অ্যাপ:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<title>Download files using a XHR2, a Worker, and saving to filesystem</title>
</head>
<body>
<script>
    var worker = new Worker('downloader.js');
    worker.onmessage = function(e) {
    console.log(e.data);
    };
    worker.postMessage({fileName: 'GoogleLogo',
                        url: 'googlelogo.png', type: 'image/png'});
</script>
</body>
</html>

downloader.js:

self.requestFileSystemSync = self.webkitRequestFileSystemSync ||
                                self.requestFileSystemSync;

function makeRequest(url) {
    try {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, false); // Note: synchronous
    xhr.responseType = 'arraybuffer';
    xhr.send();
    return xhr.response;
    } catch(e) {
    return "XHR Error " + e.toString();
    }
}

function onError(e) {
    postMessage('ERROR: ' + e.toString());
}

onmessage = function(e) {
    var data = e.data;

    // Make sure we have the right parameters.
    if (!data.fileName || !data.url || !data.type) {
    return;
    }
    
    try {
    var fs = requestFileSystemSync(TEMPORARY, 1024 * 1024 /*1MB*/);

    postMessage('Got file system.');

    var fileEntry = fs.root.getFile(data.fileName, {create: true});

    postMessage('Got file entry.');

    var arrayBuffer = makeRequest(data.url);
    var blob = new Blob([new Uint8Array(arrayBuffer)], {type: data.type});

    try {
        postMessage('Begin writing');
        fileEntry.createWriter().write(blob);
        postMessage('Writing complete');
        postMessage(fileEntry.toURL());
    } catch (e) {
        onError(e);
    }

    } catch (e) {
    onError(e);
    }
};

উপসংহার

ওয়েব ওয়ার্কার হল HTML5 এর একটি কম ব্যবহার করা এবং কম-প্রশংসিত বৈশিষ্ট্য। আমি যাদের সাথে কথা বলি তাদের বেশিরভাগ ডেভেলপারদের অতিরিক্ত কম্পিউটেশনাল সুবিধার প্রয়োজন নেই, তবে তারা শুধুমাত্র বিশুদ্ধ গণনার চেয়ে বেশি ব্যবহার করা যেতে পারে। আপনি যদি সন্দিহান হন (যেমন আমি ছিলাম), আমি আশা করি এই নিবন্ধটি আপনার মন পরিবর্তন করতে সাহায্য করেছে। ডিস্ক অপারেশন (ফাইলসিস্টেম এপিআই কল) বা একজন কর্মীকে HTTP অনুরোধের মতো জিনিসগুলি অফলোড করা একটি স্বাভাবিক উপযুক্ত এবং এটি আপনার কোডকে বিভক্ত করতে সহায়তা করে। ওয়ার্কার্সের ভিতরে থাকা HTML5 ফাইল এপিআই ওয়েব অ্যাপগুলির জন্য একটি সম্পূর্ণ নতুন ক্যান উন্মুক্ত করে যা অনেক লোক অন্বেষণ করেনি৷