সিলেক্টেড ফরম্যাট রিড: অ্যাসিঙ্ক ক্লিপবোর্ড এপিআই-এর জন্য একটি উন্নততর ডিফল্ট।

প্রশান্ত সিং
Prashant Singh

প্রকাশিত: ৩ জুলাই, ২০২৬

আপনি যদি কখনও কোনো ডকুমেন্ট এডিটর, স্প্রেডশীট অ্যাপ বা এমন কোনো অ্যাপ ব্যবহার করে থাকেন যেখানে ক্লিপবোর্ড থেকে কন্টেন্ট পেস্ট করাই প্রধান কাজ, তাহলে আপনি ব্যবহারকারীর প্রত্যাশাটি জানেন: পেস্ট করার প্রক্রিয়াটি যেন তাৎক্ষণিক হয়।

দুর্ভাগ্যবশত, অনেক ক্ষেত্রে ওয়েব অ্যাপগুলো প্রয়োজনের চেয়ে বেশি ক্লিপবোর্ড ডেটা পড়ে, যার ফলে কন্টেন্ট পেস্ট করা স্বাভাবিকের চেয়ে ধীর মনে হতে পারে, সিপিইউ সাইকেল নষ্ট হয় এবং অ্যাপটির কখনোই প্রয়োজন নেই এমন ডেটার জন্য মেমরি ব্যবহৃত হয়।

সিলেক্টেড ফরম্যাট রিড এই পারফরম্যান্স সমস্যার সমাধান করে অ্যাসিঙ্ক ক্লিপবোর্ড এপিআই-কে পরিবর্তন করার মাধ্যমে, যা ব্যবহারকারীর প্রত্যাশা আরও ভালোভাবে পূরণ করে এবং ডেভেলপারদের যা প্রয়োজন তা প্রদান করে—অর্থাৎ, শুধুমাত্র অ্যাপের জন্য প্রয়োজনীয় ফরম্যাটগুলোই রিড করে।

সমস্যাটি হলো: আগে থেকেই সব ডেটা ফরম্যাট পড়ে নেওয়া।

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

এখন পর্যন্ত, navigator.clipboard.read() সিস্টেম ক্লিপবোর্ড থেকে ডেটার প্রতিটি উপলব্ধ রূপ সংগ্রহ করত, ডেটা স্যানিটাইজ করত (যা সময়সাপেক্ষ হতে পারে, বিশেষ করে বড় আকারের HTML বা ছবির ক্ষেত্রে), এবং বাইটগুলোকে মেমরিতে ধরে রাখত, এমনকি সেইসব ফরম্যাটের জন্যও যা অ্যাপটি কখনোই ব্যবহার করত না। অব্যবহৃত পেলোড যত বড় হতো, ব্যবহারকারীকে তত বেশি অপেক্ষা করতে হতো এবং ট্যাবটি তত বেশি মেমরি ব্যবহার করত, ঠিক যখন পেস্ট করার দ্রুত প্রতিক্রিয়া সবচেয়ে বেশি জরুরি।

সমাধান: শুধু গণনা করুন, তারপর চাহিদা অনুযায়ী পড়ুন।

Chrome এবং Edge 149 থেকে, navigator.clipboard.read() মেথড দ্বারা রিটার্ন করা ClipboardItem অবজেক্টগুলো তাৎক্ষণিকভাবে ডেটা অ্যাক্সেস করার সুযোগ না দিয়ে, শুধুমাত্র ক্লিপবোর্ডে কী আছে তা বর্ণনা করে। একটি নির্দিষ্ট ফরম্যাটের জন্য প্রকৃত বাইটগুলো ক্লিপবোর্ড থেকে তখনই পড়া হয়, যখন আপনি ClipboardItem.getType(mimeType) কল করেন। API-এর মূল কাঠামো অপরিবর্তিত রয়েছে। আপনি গতকাল যে কোডটি লিখেছিলেন, সেটি আজও কাজ করবে এবং আপনাকে তাৎক্ষণিক পারফরম্যান্স সুবিধা দেবে:

// Enumerate the available MIME types.
// No payload is fetched yet.
const items = await navigator.clipboard.read();

for (const item of items) {
  if (item.types.includes('text/html')) {
    // Only read the HTML data.
    // The data is fetched (and sanitized) here only.
     const blob = await item.getType('text/html');
     useThePastedHtml(await blob.text());
     break;
   }

   // text/plain, image/png, or any other custom formats
   // stored in the clipboard are never read.
}

এর আরেকটি পারফরম্যান্স সুবিধা হলো ক্যাশিং স্বয়ংক্রিয়। একই ClipboardItem উপর দুইবার getType('text/html') কল করলে তা সিস্টেম ক্লিপবোর্ড থেকে কেবল একবারই পড়ে এবং দ্বিতীয়বার কলের সময় ক্যাশ করা Blob ফেরত দেয়।

সুবিধাগুলো

ল্যাটেন্সি। navigator.clipboard.read() কল করার সময় যে কাজগুলো করার প্রয়োজন হতো, যেমন বিভিন্ন প্রসেসের মধ্যে বাইট কপি করা, HTML স্যানিটাইজ করা বা ইমেজ ডিকোড করা, সেগুলো এখন শুধুমাত্র আপনার অ্যাপের প্রয়োজনীয় ফরম্যাটগুলোর জন্যই সম্পন্ন হয়। যে অ্যাপগুলো কেবল একটি ফরম্যাট রিড করে, তারাই সবচেয়ে বেশি সাশ্রয় লাভ করে। আপনি যত বেশি ফরম্যাট বাদ দেবেন, লাভও তত বেশি হবে। HTML সবচেয়ে বেশি লাভবান হয় কারণ HTML স্যানিটাইজেশন ব্যয়বহুল।

মেমরি। আগে, ক্লিপবোর্ডে ৫০ মেগাবাইটের কোনো ছবি থাকলে navigator.clipboard.read() কল করলে, ClipboardItem টি মুক্ত না হওয়া পর্যন্ত ওয়েব পেজের রেন্ডারার মেমরিতে ৫০ মেগাবাইট জায়গা ব্যবহৃত হতো, এমনকি অ্যাপটির শুধু ডেটার text/plain সংস্করণটির প্রয়োজন হলেও। এখন, ClipboardItem.getType() কল করার সময় আপনার অ্যাপ যে ফরম্যাটগুলো পড়ে, শুধু সেগুলোই রেন্ডারার প্রসেসে মেমরি ব্যবহার করে। ডকুমেন্ট এডিটর, মেইল ​​কম্পোজার বা ডিজাইন টুলের মতো যেসব অ্যাপে পেস্ট করা সাধারণ ব্যাপার, সেগুলোর জন্য এটি পেস্ট করার সময় মেমরির ব্যবহার উল্লেখযোগ্যভাবে কমিয়ে দেয়, বিশেষ করে মাল্টি-ট্যাব সেশনে যেখানে একাধিক এডিটর একই সাথে ক্লিপবোর্ড পড়তে পারে।

কোনো অপ্ট-ইন করার প্রয়োজন নেই। ওয়েবের প্রতিটি সাইট স্বয়ংক্রিয়ভাবে এই সুবিধাগুলো পেয়ে যায়। আপনাকে কোড মাইগ্রেট করতে বা ফিচার ডিটেকশন লজিকের পিছনে কোড গেট করার দরকার নেই।

একটি আচরণগত পরিবর্তন সম্পর্কে সচেতন থাকতে হবে।

পরবর্তীতে ডেটা পড়লে আচরণে একটি সামান্য পরিবর্তন আসে: navigator.clipboard.read() কলটি সমাধান হওয়ার মুহূর্তে ` ClipboardItem অবজেক্টটি আর ক্লিপবোর্ডের একটি স্থির চিত্র থাকে না।

যখন read() কল করা হয় এবং এটি একটি ClipboardItem রিটার্ন করে, তখন এই আইটেমটি সিস্টেম ক্লিপবোর্ডে থাকা ডেটার জন্য শুধুমাত্র একটি লেজি হ্যান্ডেল হিসেবে কাজ করে। যদি read() কল করার পর থেকে পরবর্তীতে getType() কল করার মধ্যে ক্লিপবোর্ডের বিষয়বস্তু পরিবর্তিত হয়, তাহলে সেই কলটি একটি InvalidStateError সহ বাতিল হয়ে যাবে। এমনকি একই ClipboardItem এ পূর্বে সফলভাবে রিড করা কোনো ফরম্যাটের ক্ষেত্রেও এটি প্রযোজ্য।

// Read from the clipboard.
const items = await navigator.clipboard.read();
// Get the first ClipboardItem.
const item = items[0];

// Actually fetch the data now, which works fine.
const text = await item.getType('text/plain');

// The user writes something new to the clipboard
// by copying from another app, or your own code writes to
// the clipboard again.
await navigator.clipboard.writeText('something new');

// Fetching the data from the earlier ClipboardItem
// rejects with InvalidStateError, because the contents
// of the clipboard changed.
const html = await item.getType('text/html');

এর কারণ হলো, অন্যথায় ক্লিপবোর্ডে আর প্রতিফলিত না হওয়া ডেটা ফেরত দিলে তা বিভ্রান্তিকর হবে এবং এমন সব সমস্যার জন্ম দেবে যা ডিবাগ করা কঠিন হয়ে পড়বে।

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

এখানে একটি উদাহরণ দেওয়া হল যেখানে এই পরিবর্তনটি একটি সমস্যা হয়ে উঠতে পারে: window ClipboardItem অবজেক্ট ক্যাশ করা, সেগুলিকে একটি ক্লিপবোর্ড-হিস্ট্রি UI-তে প্রদর্শন করা, অথবা getType() কল করার আগে ব্যবহারকারীর ইন্টারঅ্যাকশনের জন্য অপেক্ষা করা। এই ধরনের পরিস্থিতিতে সমস্যা এড়াতে:

  • getType() কলগুলোকে try / catch ব্লকের মধ্যে রাখুন, এবং InvalidStateError এমন একটি সংকেত হিসেবে বিবেচনা করুন যা বোঝায় যে ক্লিপবোর্ডটি অন্য ডেটায় চলে গেছে এবং কোডটিকে আবার পড়তে হবে।
  • ক্লিপবোর্ডের ডেটা ধরে রাখার প্রয়োজন হলে, Blob টিকে getType() করার সাথে সাথেই আপনার নিজের স্ট্রাকচারে কপি করে নিন। ClipboardItem দীর্ঘমেয়াদী স্টোরেজ হিসেবে বিবেচনা করবেন না।
  • পুরনো হ্যান্ডেলগুলোকে আগে থেকেই বাতিল করতে clipboardChange ইভেন্টটি ব্যবহার করুন।

মান এবং ব্রাউজার সমর্থন

সিলেক্টিভ ফরম্যাট রিড হলো ক্লিপবোর্ড এপিআই স্পেসিফিকেশনের একটি পরিবর্তন, যা ওয়েব এডিটিং ওয়ার্কিং গ্রুপ এবং মাইক্রোসফট এজ ওয়েব প্ল্যাটফর্ম টিমের উদ্যোগে আনা হয়েছে।

সাফারিও এই আচরণ সমর্থন করে, এবং ফায়ারফক্স একটি ইতিবাচক মানদণ্ডগত অবস্থান ও এর সাথে সামঞ্জস্য বিধানের অভিপ্রায় ব্যক্ত করেছে।

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