এপিআই অনুরোধের সময়সীমা আনা?


100

আমার একটি fetch-api POSTঅনুরোধ আছে:

fetch(url, {
  method: 'POST',
  body: formData,
  credentials: 'include'
})

আমি জানতে চাই এর জন্য ডিফল্ট সময়সীমা কী? এবং আমরা কীভাবে এটি 3 সেকেন্ড বা অনির্দিষ্ট সেকেন্ডের মতো কোনও নির্দিষ্ট মানটিতে সেট করতে পারি?

উত্তর:


78

সম্পাদনা করুন 1

মন্তব্যে নির্দেশিত হিসাবে, মূল উত্তরের কোডটি প্রতিশ্রুতিটি সমাধান / প্রত্যাখ্যাত হওয়ার পরেও টাইমারটি চালিয়ে যায়।

নীচের কোডটি এই সমস্যার সমাধান করে।

function timeout(ms, promise) {
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      reject(new Error('TIMEOUT'))
    }, ms)

    promise
      .then(value => {
        clearTimeout(timer)
        resolve(value)
      })
      .catch(reason => {
        clearTimeout(timer)
        reject(reason)
      })
  })
}


আসল উত্তর

এটিতে একটি নির্দিষ্ট ডিফল্ট নেই; স্পেসিফিকেশন মোটেও সময়সীমা নিয়ে আলোচনা করে না।

আপনি সাধারনত প্রতিশ্রুতির জন্য আপনার নিজস্ব টাইমআউট র‌্যাপার বাস্তবায়ন করতে পারেন:

// Rough implementation. Untested.
function timeout(ms, promise) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      reject(new Error("timeout"))
    }, ms)
    promise.then(resolve, reject)
  })
}

timeout(1000, fetch('/hello')).then(function(response) {
  // process response
}).catch(function(error) {
  // might be a timeout error
})

বর্ণনা অনুযায়ী https://github.com/github/fetch/issues/175 মন্তব্য https://github.com/mislav


27
কেন এটি গৃহীত উত্তর? প্রতিশ্রুতি মিটিয়ে গেলেও এখানে সেটটাইমআউট চলতে থাকবে। এর থেকে আরও ভাল সমাধান হ'ল
রডট্যাড

4
: @radtad mislav তার পদ্ধতির যে থ্রেড নিচে কমে defends github.com/github/fetch/issues/175#issuecomment-284787564 । সময়সীমা স্থির হয় তা বিবেচ্য নয়, কারণ .reject()ইতিমধ্যে সমাধান হওয়া প্রতিশ্রুতিতে কল করা কিছুই হয় না।
মার্ক অ্যামেরি

4
যদিও 'আনতে' ফাংশন সময়সীমা দ্বারা প্রত্যাখ্যান করা হয়েছে, ব্যাকগ্রাউন্ড টিসিপি সংযোগটি বন্ধ নেই। আমি কীভাবে আমার নোড প্রক্রিয়াটি নিখুঁতভাবে ছেড়ে দিতে পারি?
প্রগ্রে কুইস্টার

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

4
পছন্দ করুন আপনি যে উত্তরটি নির্দেশ করেছেন তা টিসিপি সংযোগটিও ভেঙে দেয় না।
ম্যাটিউস পাইরেস

143

আমি সত্যিই এই থেকে পরিষ্কার পদ্ধতির পছন্দ সারকথা ব্যবহার Promise.race

fetchWithTimeout.js

export default function (url, options, timeout = 7000) {
    return Promise.race([
        fetch(url, options),
        new Promise((_, reject) =>
            setTimeout(() => reject(new Error('timeout')), timeout)
        )
    ]);
}

main.js

import fetch from './fetchWithTimeout'

// call as usual or with timeout as 3rd argument

fetch('http://google.com', options, 5000) // throw after max 5 seconds timeout error
.then((result) => {
    // handle result
})
.catch((e) => {
    // handle errors and timeout error
})

4
সময়সীমা শেষ fetchহওয়ার পরে যদি কোনও ত্রুটি ঘটে তবে এটি "আনহ্যান্ডলড প্রত্যাখ্যান" করে । এই (হ্যান্ডলিং দ্বারা সমাধান করা যেতে পারে .catch) fetchব্যর্থতা এবং যদি সময়সীমার এখনও ঘটেনি rethrowing।
লাইনিলো

4
এই প্রোগ্রামটিতে এই AbortController সঙ্গে উন্নত অতিরিক্ত, যখন প্রত্যাখ্যান দেখতে হতে পারে stackoverflow.com/a/47250621
রিজকিট

আনয়ন সফলভাবে সফল হলে সময়সীমা পরিষ্কার করা আরও ভাল।
Bob9630

105

AbortController ব্যবহার করে , আপনি এটি করতে সক্ষম হবেন:

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

const fetchPromise = fetch(url, {signal});

// 5 second timeout:
const timeoutId = setTimeout(() => controller.abort(), 5000);


fetchPromise.then(response => {
  // completed request before timeout fired

  // If you only wanted to timeout the request, not the response, add:
  // clearTimeout(timeoutId);
})

14
এটি প্রতিশ্রুতি-রেস-সমাধানের চেয়ে আরও ভাল দেখায় কারণ এটি সম্ভবত পূর্ববর্তী প্রতিক্রিয়া গ্রহণের পরিবর্তে অনুরোধটি বাতিল করে দেয়। আমি ভুল হলে শুধরে.
কার্ল অ্যাডলার

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

এটি অ্যাওর্টকন্ট্রোলার কী তা ব্যাখ্যা করতে পারে না (অলসদের পক্ষে এটি আরও সহজ করার জন্য আমি উত্তরের একটি লিঙ্ক যুক্ত করেছি) তবে এটি এখন পর্যন্ত সেরা উত্তর, কারণ এটি কেবলমাত্র একটি অনুরোধ উপেক্ষা করে এই সত্যটি তুলে ধরেছে যে এটি এখনও নেই মুলতুবি নেই। দুর্দান্ত উত্তর।
অরেলিও

4
"অলসদের পক্ষে এটি আরও সহজ করার জন্য আমি উত্তরের একটি লিঙ্ক যুক্ত করেছি" - এটি টিবিএইচ বিধি অনুযায়ী সত্যই একটি লিঙ্ক এবং আরও তথ্যের সাথে আসা উচিত। তবে উত্তরটি উন্নত করার জন্য আপনাকে ধন্যবাদ।
জে উইক

6
কোনও উত্তর না দিয়ে এই উত্তরটি পাওয়া ভাল কারণ লোকেরা নিটপিকারি, টিবিএইচ দ্বারা বন্ধ রয়েছে
মাইকেল টেরি

21

অন্তহীন 'দুর্দান্ত উত্তরের উপর বিল্ডিং , আমি একটি সহায়ক ইউটিলিটি ফাংশন তৈরি করেছি।

const fetchTimeout = (url, ms, { signal, ...options } = {}) => {
    const controller = new AbortController();
    const promise = fetch(url, { signal: controller.signal, ...options });
    if (signal) signal.addEventListener("abort", () => controller.abort());
    const timeout = setTimeout(() => controller.abort(), ms);
    return promise.finally(() => clearTimeout(timeout));
};
  1. যদি উত্সটি আনার আগে সময়সীমাটি পৌঁছে যায় তবে আনতে হবে বাতিল করা।
  2. সময়সীমাটি পৌঁছানোর আগে যদি উত্সটি আনা হয় তবে সময়সীমাটি সাফ হয়ে যায়।
  3. যদি ইনপুট সিগন্যালটি বাতিল করা হয় তবে আনতে হবে বাতিল এবং সময়সীমা সাফ করা হয়েছে।
const controller = new AbortController();

document.querySelector("button.cancel").addEventListener("click", () => controller.abort());

fetchTimeout("example.json", 5000, { signal: controller.signal })
    .then(response => response.json())
    .then(console.log)
    .catch(error => {
        if (error.name === "AbortError") {
            // fetch aborted either due to timeout or due to user clicking the cancel button
        } else {
            // network error or json parsing error
        }
    });

আশা করি এইটি কাজ করবে.


9

ফেচ এপিআই-তে এখনও কোনও সময়সীমা সমর্থন নেই। কিন্তু এটি একটি প্রতিশ্রুতি মোড়ানো দ্বারা অর্জন করা যেতে পারে।

যেমন।

  function fetchWrapper(url, options, timeout) {
    return new Promise((resolve, reject) => {
      fetch(url, options).then(resolve, reject);

      if (timeout) {
        const e = new Error("Connection timed out");
        setTimeout(reject, timeout, e);
      }
    });
  }

আমি এটিকে আরও ভাল, একবারের চেয়ে কম বারবার ব্যবহার করতে চাই।
ডান্ডাভিস

4
অনুরোধটি এখানে টাইমআউট করার পরে বাতিল করা হয়নি, তাই না? এটি ওপি-র পক্ষে ভাল হতে পারে তবে কখনও কখনও আপনি কোনও অনুরোধ ক্লায়েন্ট-সাইড বাতিল করতে চান।
ট্রাইসিস

4
@ ট্রিসিস ভাল, হ্যাঁ সম্প্রতি AbortController এর সাথে অ্যাওর্ট আনার জন্য একটি সমাধান কার্যকর করা হয়েছে , তবে এখনও সীমিত ব্রাউজার সমর্থন সহ পরীক্ষামূলক। আলোচনা
কোড-জাফ

মজার বিষয়, আইই এবং এজ কেবল এটিকে সমর্থন করে! মোবাইল মোজিলা সাইটটি যদি আবার অভিনয় না করে ...
ট্রিপসিস

ফায়ারফক্স 57 এর পর থেকে এটি সমর্থন করে আসছে। :: ক্রোমে দেখা ::
ফ্রাঙ্কলিন ইউ

7

সম্পাদনা : আনতে অনুরোধটি এখনও পটভূমিতে চলবে এবং সম্ভবত আপনার কনসোলে কোনও ত্রুটি লগ করবে।

আসলে Promise.raceপদ্ধতির ভাল।

উল্লেখের জন্য এই লিঙ্কটি দেখুন () Promise.race

রেসের অর্থ হ'ল সমস্ত প্রতিশ্রুতি একই সাথে চলবে এবং প্রতিশ্রুতিগুলির মধ্যে একটির মূল্য ফেরতের সাথে সাথে দৌড় বন্ধ হয়ে যাবে। অতএব, শুধুমাত্র একটি মান ফেরত আসবে । আনার সময় শেষ হলে আপনি কল করতে কোনও ফাংশনও পাস করতে পারেন।

fetchWithTimeout(url, {
  method: 'POST',
  body: formData,
  credentials: 'include',
}, 5000, () => { /* do stuff here */ });

এটি যদি আপনার আগ্রহের দিকে চালিত করে তবে সম্ভাব্য বাস্তবায়ন হ'ল:

function fetchWithTimeout(url, options, delay, onTimeout) {
  const timer = new Promise((resolve) => {
    setTimeout(resolve, delay, {
      timeout: true,
    });
  });
  return Promise.race([
    fetch(url, options),
    timer
  ]).then(response => {
    if (response.timeout) {
      onTimeout();
    }
    return response;
  });
}

2

আপনি একটি টাইমআউটপ্রাইম র‌্যাপার তৈরি করতে পারেন

function timeoutPromise(timeout, err, promise) {
  return new Promise(function(resolve,reject) {
    promise.then(resolve,reject);
    setTimeout(reject.bind(null,err), timeout);
  });
}

তারপরে আপনি কোনও প্রতিশ্রুতি মোড়ানো করতে পারেন

timeoutPromise(100, new Error('Timed Out!'), fetch(...))
  .then(...)
  .catch(...)  

এটি আসলে অন্তর্নিহিত সংযোগটি বাতিল করবে না তবে আপনাকে একটি প্রতিশ্রুতি সময়সীমার অনুমতি দেবে।
রেফারেন্স


2

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

1) ফায়ারফক্স - 90 সেকেন্ড

about:configফায়ারফক্স URL টাইপ করুন । কীটির সাথে সম্পর্কিত মানটি সন্ধান করুনnetwork.http.connection-timeout

2) ক্রোম - 300 সেকেন্ড

সূত্র



0

ব্যবহার সি-promise2 cancellable liberal এর সংক্ষিপ্ত রূপ সময়সীমার সঙ্গে আনা এই এক (অনুরূপ হতে পারে লাইভ jsfiddle ডেমো ):

import CPromise from "c-promise2"; // npm package

function fetchWithTimeout(url, {timeout, ...fetchOptions}= {}) {
    return new CPromise((resolve, reject, {signal}) => {
        fetch(url, {...fetchOptions, signal}).then(resolve, reject)
    }, timeout)
}
        
const chain = fetchWithTimeout("https://run.mocky.io/v3/753aa609-65ae-4109-8f83-9cfe365290f0?mocky-delay=10s", {timeout: 5000})
    .then(request=> console.log('done'));
    
// chain.cancel(); - to abort the request before the timeout

এই এনপিএম প্যাকেজ হিসাবে সিপি-ফেচ করুন

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.