বাতিলযোগ্য আনা

"আনয়ন বাতিল করা" এর জন্য আসল গিটহাব ইস্যুটি 2015 সালে খোলা হয়েছিল। এখন, যদি আমি 2015কে 2017 (চলতি বছর) থেকে সরিয়ে নিই, তবে আমি 2 পাব। এটি গণিতের একটি ত্রুটি প্রদর্শন করে, কারণ 2015 আসলে "চিরকাল" আগে ছিল। .

2015 ছিল যখন আমরা প্রথমবার চলমান ফেচ বাতিল করা অন্বেষণ শুরু করেছি, এবং 780টি গিটহাব মন্তব্য, কয়েকটি মিথ্যা শুরু এবং 5টি পুল অনুরোধের পরে, আমরা অবশেষে ফায়ারফক্স 57 সহ ব্রাউজারগুলিতে অবতরণ বাতিলযোগ্য আনয়ন করেছি।

আপডেট: Noooope, আমি ভুল ছিল. এজ 16 প্রথমে গর্ভপাত সমর্থন সহ অবতরণ! এজ দলকে অভিনন্দন!

আমি পরে ইতিহাসে ডুব দেব, কিন্তু প্রথমে, API:

নিয়ামক + সংকেত কৌশল

AbortController এবং AbortSignal সাথে দেখা করুন:

const controller = new AbortController();
const signal = controller.signal;

কন্ট্রোলারের শুধুমাত্র একটি পদ্ধতি আছে:

controller.abort();

আপনি যখন এটি করেন, এটি সংকেতকে অবহিত করে:

signal.addEventListener('abort', () => {
    // Logs true:
    console.log(signal.aborted);
});

এই APIটি DOM স্ট্যান্ডার্ড দ্বারা সরবরাহ করা হয়েছে, এবং এটি সম্পূর্ণ API। এটি ইচ্ছাকৃতভাবে জেনেরিক তাই এটি অন্যান্য ওয়েব স্ট্যান্ডার্ড এবং জাভাস্ক্রিপ্ট লাইব্রেরি দ্বারা ব্যবহার করা যেতে পারে।

সংকেত বাতিল করুন এবং আনুন

ফেচ একটি AbortSignal নিতে পারে। উদাহরণস্বরূপ, আপনি কিভাবে 5 সেকেন্ডের পরে একটি ফিচ টাইমআউট করবেন তা এখানে রয়েছে:

const controller = new AbortController();
const signal = controller.signal;

setTimeout(() => controller.abort(), 5000);

fetch(url, { signal }).then(response => {
    return response.text();
}).then(text => {
    console.log(text);
});

আপনি যখন একটি আনয়ন বাতিল করেন, তখন এটি অনুরোধ এবং প্রতিক্রিয়া উভয়ই বাতিল করে, তাই প্রতিক্রিয়া বডির যেকোন পাঠ (যেমন response.text() )ও বাতিল করা হয়।

এখানে একটি ডেমো রয়েছে – লেখার সময়, একমাত্র ব্রাউজার যা এটিকে সমর্থন করে তা হল Firefox 57। এছাড়াও, নিজেকে বন্ধন করুন, ডেমো তৈরিতে ডিজাইনের দক্ষতা সহ কেউ জড়িত ছিল না।

বিকল্পভাবে, একটি অনুরোধ বস্তুতে সংকেত দেওয়া যেতে পারে এবং পরে আনার জন্য পাস করা যেতে পারে:

const controller = new AbortController();
const signal = controller.signal;
const request = new Request(url, { signal });

fetch(request);

এটি কাজ করে কারণ request.signal হল একটি AbortSignal

একটি বাতিল করা আনার প্রতিক্রিয়া

আপনি যখন একটি অ্যাসিঙ্ক অপারেশন বাতিল করেন, তখন প্রতিশ্রুতিটি AbortError নামে একটি DOMException দিয়ে প্রত্যাখ্যান করে:

fetch(url, { signal }).then(response => {
    return response.text();
}).then(text => {
    console.log(text);
}).catch(err => {
    if (err.name === 'AbortError') {
    console.log('Fetch aborted');
    } else {
    console.error('Uh oh, an error!', err);
    }
});

আপনি প্রায়শই একটি ত্রুটি বার্তা দেখাতে চান না যদি ব্যবহারকারী অপারেশনটি বাতিল করে দেয়, কারণ এটি একটি "ত্রুটি" নয় যদি আপনি সফলভাবে ব্যবহারকারী যা বলেছেন তা করেন। এটি এড়াতে, একটি if-স্টেটমেন্ট ব্যবহার করুন যেমন উপরের একটি গর্ভপাত ত্রুটিগুলি বিশেষভাবে পরিচালনা করতে।

এখানে একটি উদাহরণ দেওয়া হল যা ব্যবহারকারীকে সামগ্রী লোড করার জন্য একটি বোতাম এবং ত্যাগ করার জন্য একটি বোতাম দেয়৷ যদি আনয়ন ত্রুটি, একটি ত্রুটি দেখানো হয়, যদি না এটি একটি বাতিল ত্রুটি হয়:

// This will allow us to abort the fetch.
let controller;

// Abort if the user clicks:
abortBtn.addEventListener('click', () => {
    if (controller) controller.abort();
});

// Load the content:
loadBtn.addEventListener('click', async () => {
    controller = new AbortController();
    const signal = controller.signal;

    // Prevent another click until this fetch is done
    loadBtn.disabled = true;
    abortBtn.disabled = false;

    try {
    // Fetch the content & use the signal for aborting
    const response = await fetch(contentUrl, { signal });
    // Add the content to the page
    output.innerHTML = await response.text();
    }
    catch (err) {
    // Avoid showing an error message if the fetch was aborted
    if (err.name !== 'AbortError') {
        output.textContent = "Oh no! Fetching failed.";
    }
    }

    // These actions happen no matter how the fetch ends
    loadBtn.disabled = false;
    abortBtn.disabled = true;
});

এখানে একটি ডেমো রয়েছে - লেখার সময়, শুধুমাত্র ব্রাউজারগুলি যেগুলি এটি সমর্থন করে তা হল এজ 16 এবং ফায়ারফক্স 57৷

একটি সংকেত, অনেকগুলি আনা

একটি একক সংকেত একসাথে অনেকগুলি ফেচ বাতিল করতে ব্যবহার করা যেতে পারে:

async function fetchStory({ signal } = {}) {
    const storyResponse = await fetch('/story.json', { signal });
    const data = await storyResponse.json();

    const chapterFetches = data.chapterUrls.map(async url => {
    const response = await fetch(url, { signal });
    return response.text();
    });

    return Promise.all(chapterFetches);
}

উপরের উদাহরণে, একই সংকেত প্রাথমিক আনার জন্য এবং সমান্তরাল অধ্যায় আনার জন্য ব্যবহৃত হয়। এখানে আপনি কিভাবে fetchStory ব্যবহার করবেন:

const controller = new AbortController();
const signal = controller.signal;

fetchStory({ signal }).then(chapters => {
    console.log(chapters);
});

এই ক্ষেত্রে, controller.abort() কল করলে যেটি আনার প্রক্রিয়া চলছে তা বাতিল হয়ে যাবে।

ভবিষ্যৎ

অন্যান্য ব্রাউজার

এজ এটি প্রথম পাঠানোর জন্য একটি দুর্দান্ত কাজ করেছে, এবং ফায়ারফক্স তাদের ট্রেইলে উত্তপ্ত। তাদের প্রকৌশলীরা পরীক্ষার স্যুট থেকে প্রয়োগ করেছিলেন যখন স্পেক লেখা হচ্ছে। অন্যান্য ব্রাউজারগুলির জন্য, এখানে অনুসরণ করার টিকিট রয়েছে:

একজন সেবাকর্মীর মধ্যে

আমাকে পরিষেবা কর্মী অংশগুলির জন্য স্পেকটি শেষ করতে হবে, তবে এখানে পরিকল্পনাটি রয়েছে:

আমি আগে উল্লেখ করেছি, প্রতিটি Request বস্তুর একটি signal সম্পত্তি আছে। একটি পরিষেবা কর্মীর মধ্যে, fetchEvent.request.signal যদি পৃষ্ঠাটি আর প্রতিক্রিয়াতে আগ্রহী না হয় তবে স্থগিত হওয়ার সংকেত দেবে৷ ফলস্বরূপ, এই মত কোড শুধু কাজ করে:

addEventListener('fetch', event => {
    event.respondWith(fetch(event.request));
});

যদি পৃষ্ঠাটি আনয়ন বাতিল করে, fetchEvent.request.signal সংকেত স্থগিত করে, তাই পরিষেবা কর্মীর মধ্যে আনাও বাতিল হয়ে যায়।

আপনি যদি event.request ব্যতীত অন্য কিছু আনছেন, তাহলে আপনাকে আপনার কাস্টম ফেচ(গুলি) এ সিগন্যালটি পাস করতে হবে।

addEventListener('fetch', event => {
    const url = new URL(event.request.url);

    if (event.request.method == 'GET' && url.pathname == '/about/') {
    // Modify the URL
    url.searchParams.set('from-service-worker', 'true');
    // Fetch, but pass the signal through
    event.respondWith(
        fetch(url, { signal: event.request.signal })
    );
    }
});

এটি ট্র্যাক করার জন্য বিশেষত্ব অনুসরণ করুন – এটি বাস্তবায়নের জন্য প্রস্তুত হয়ে গেলে আমি ব্রাউজার টিকিটের লিঙ্ক যুক্ত করব।

ইতিহাস

হ্যাঁ… এই তুলনামূলকভাবে সহজ এপিআই একসাথে আসতে অনেক সময় লেগেছে। কারণটা এখানে:

API মতানৈক্য

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

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

আপনি যদি এমন একটি বস্তু ফেরত দিতে চান যা একটি প্রতিক্রিয়া প্রদান করে, তবে বাতিলও করতে পারে, আপনি একটি সাধারণ মোড়ক তৈরি করতে পারেন:

function abortableFetch(request, opts) {
    const controller = new AbortController();
    const signal = controller.signal;

    return {
    abort: () => controller.abort(),
    ready: fetch(request, { ...opts, signal })
    };
}

TC39 এ False শুরু হয়

একটি বাতিল ক্রিয়াকে একটি ত্রুটি থেকে আলাদা করার প্রচেষ্টা ছিল৷ এতে "বাতিল" বোঝানোর জন্য একটি তৃতীয় প্রতিশ্রুতি এবং সিঙ্ক এবং অ্যাসিঙ্ক কোড উভয় ক্ষেত্রেই বাতিলকরণ পরিচালনা করার জন্য কিছু নতুন সিনট্যাক্স অন্তর্ভুক্ত রয়েছে:

করবেন না

আসল কোড নয় - প্রস্তাব প্রত্যাহার করা হয়েছিল

    try {
      // Start spinner, then:
      await someAction();
    }
    catch cancel (reason) {
      // Maybe do nothing?
    }
    catch (err) {
      // Show error message
    }
    finally {
      // Stop spinner
    }

যখন একটি ক্রিয়া বাতিল করা হয় তখন করা সবচেয়ে সাধারণ জিনিস কিছুই নয়। উপরের প্রস্তাবটি বাতিলকরণকে ত্রুটিগুলি থেকে আলাদা করেছে তাই আপনাকে বিশেষভাবে গর্ভপাতের ত্রুটিগুলি পরিচালনা করার দরকার নেই৷ catch cancel আপনাকে বাতিল ক্রিয়া সম্পর্কে শুনতে দেয়, তবে বেশিরভাগ সময় আপনার প্রয়োজন হয় না।

এটি TC39-এ প্রথম পর্যায়ে পৌঁছেছে, কিন্তু ঐকমত্য অর্জিত হয়নি এবং প্রস্তাবটি প্রত্যাহার করা হয়েছে

আমাদের বিকল্প প্রস্তাব, AbortController , কোন নতুন সিনট্যাক্সের প্রয়োজন ছিল না, তাই এটি TC39-এর মধ্যে নির্দিষ্ট করার কোন মানে ছিল না। জাভাস্ক্রিপ্ট থেকে আমাদের যা কিছু প্রয়োজন তা আগে থেকেই ছিল, তাই আমরা ওয়েব প্ল্যাটফর্মের মধ্যে ইন্টারফেসগুলিকে সংজ্ঞায়িত করেছি, বিশেষ করে DOM স্ট্যান্ডার্ড । একবার আমরা সেই সিদ্ধান্ত নিলে, বাকিরা তুলনামূলকভাবে দ্রুত একত্রিত হয়।

বড় বৈশিষ্ট পরিবর্তন

XMLHttpRequest বছরের পর বছর ধরে বাতিল করা হয়েছে, কিন্তু স্পেকটি বেশ অস্পষ্ট ছিল। কোন পয়েন্টে অন্তর্নিহিত নেটওয়ার্ক ক্রিয়াকলাপ এড়ানো যেতে পারে, বা বন্ধ করা যেতে পারে, বা abort() কল করা এবং ফেচ সম্পূর্ণ করার মধ্যে একটি রেস শর্ত থাকলে কী ঘটেছিল তা স্পষ্ট ছিল না।

আমরা এই সময়ে এটি ঠিক করতে চেয়েছিলাম, কিন্তু এর ফলে একটি বড় বৈশিষ্ট পরিবর্তন হয়েছে যার জন্য অনেক পর্যালোচনার প্রয়োজন ছিল (এটি আমার দোষ, এবং আমাকে এটির মাধ্যমে টেনে আনার জন্য অ্যান ভ্যান কেস্টেরেন এবং ডোমেনিক ডেনিকোলাকে অনেক ধন্যবাদ) এবং একটি শালীন সেট পরীক্ষা

কিন্তু আমরা এখন এখানে! অ্যাসিঙ্ক অ্যাকশন বাতিল করার জন্য আমাদের কাছে একটি নতুন ওয়েব আদিম আছে, এবং একাধিক ফেচ একবারে নিয়ন্ত্রণ করা যেতে পারে! আরও নিচে, আমরা একটি আনার পুরো জীবনব্যাপী অগ্রাধিকার পরিবর্তনগুলি সক্ষম করার দিকে নজর দেব, এবং একটি উচ্চ-স্তরের এপিআই আনার অগ্রগতি পর্যবেক্ষণ করব৷