javascript - আমি কিভাবে একটি অ্যাসিঙ্ক্রোনাস কল থেকে প্রতিক্রিয়া ফেরত দিতে পারি?




ajax asynchronous (20)

আমি একটি ফাংশন foo যা একটি অ্যাজাক্স অনুরোধ করে তোলে। আমি কিভাবে foo থেকে প্রতিক্রিয়া ফিরে আসতে পারি?

আমি success কলব্যাক থেকে মানটি ফেরত দেওয়ার চেষ্টা করেছি এবং ফাংশনের ভেতর একটি স্থানীয় ভেরিয়েবলের প্রতিক্রিয়াটি বরাদ্দ করার এবং সেটি ফেরত দেওয়ার চেষ্টা করেছি, কিন্তু সেগুলির কোনটি আসলে প্রতিক্রিয়াটি ফেরত দেয় না।

function foo() {
    var result;

    $.ajax({
        url: '...',
        success: function(response) {
            result = response;
            // return response; // <- I tried that one as well
        }
    });

    return result;
}

var result = foo(); // It always ends up being `undefined`.

→ বিভিন্ন উদাহরণ সহ অ্যাসাইন আচরণের আরো সাধারণ ব্যাখ্যা করার জন্য, আমার ফাংশনটির ভিতরে এটি সংশোধন করার পরে কেন আমার পরিবর্তনশীল unaltered? - অ্যাসিঙ্ক্রোনাস কোড রেফারেন্স

→ যদি আপনি ইতিমধ্যে সমস্যাটি বুঝতে পারেন, নিচের সম্ভাব্য সমাধানগুলিতে যান।

সমস্যাটি

Ajax asynchronous দাঁড়িয়েছে। এর মানে হল অনুরোধ পাঠানো (অথবা প্রতিক্রিয়া গ্রহণ করা) স্বাভাবিক মৃত্যুদন্ড প্রবাহের বাইরে নেওয়া হয়। আপনার উদাহরণে, $.ajax অবিলম্বে ফেরত এবং পরবর্তী বিবৃতি, return result; , success কলব্যাক এমনকি আপনি বলা হয় হিসাবে পাস ফাংশন আগে মৃত্যুদন্ড কার্যকর করা হয়।

এখানে একটি উপমা রয়েছে যা আশা করে সমান সমান এবং সমান সমৃদ্ধ প্রবাহের মধ্যে পার্থক্য তৈরি করে:

সমলয়

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

যখন আপনি "স্বাভাবিক" কোড সহ একটি ফাংশন কল করেন তখন একই ঘটছে:

function findItem() {
    var item;
    while(item_not_found) {
        // search
    }
    return item;
}

var item = findItem();

// Do something with item
doSomethingElse();

যদিও এটি findItem চালানোর জন্য অনেক সময় findItem পারে তবে var item = findItem(); ফাংশন ফলাফল ফেরত না হওয়া পর্যন্ত অপেক্ষা করতে হবে

অসমনিয়ত

আপনি একই কারণে আবার আপনার বন্ধুর কল। কিন্তু এই সময় আপনি তাকে বলবেন যে আপনি তাড়াতাড়ি আছেন এবং আপনাকে আপনার মোবাইল ফোনে কল করতে হবে । আপনি আপ ঝুলন্ত, ঘর ছেড়ে এবং যাই হোক না কেন আপনি করতে পরিকল্পনা। একবার আপনার বন্ধুর আপনাকে ফোন করার পরে, আপনি যে তথ্যটি দিয়েছেন সেটির সাথে আপনি আচরণ করছেন।

এটি ঠিক কী হচ্ছে যখন আপনি একটি অ্যাজাক্স অনুরোধ করবেন।

findItem(function(item) {
    // Do something with item
});
doSomethingElse();

প্রতিক্রিয়া অপেক্ষা করার পরিবর্তে, মৃত্যুদন্ড অবিলম্বে চলতে থাকে এবং অজ্যাক্স কলের পরে বিবৃতি কার্যকর করা হয়। প্রতিক্রিয়া অবশেষে, প্রতিক্রিয়াটি একবার পাওয়ার পরে আপনি কল করার জন্য একটি ফাংশন প্রদান করেন, একটি কলব্যাক (কিছু লক্ষ্য করবেন? ফিরে কল করবেন ?)। কলব্যাক কল করার আগে যে কল এর পরে আসছে যে কোনো বিবৃতি কার্যকর করা হয়।

সমাধান (গুলি)

জাভাস্ক্রিপ্ট এর অ্যাসিঙ্ক্রোনাস প্রকৃতি আলিঙ্গন! নির্দিষ্ট অ্যাসিঙ্ক্রোনাস ক্রিয়াকলাপগুলি সমলয় সমতুল্য সরবরাহ করে (তাই "অজ্যাক্স" করে), এটি সাধারণত তাদের ব্যবহার করার জন্য নিরুৎসাহিত হয়, বিশেষ করে ব্রাউজার প্রসঙ্গে।

কেন আপনি খারাপ জিজ্ঞাসা করা হয়?

জাভাস্ক্রিপ্ট ব্রাউজারের UI থ্রেডে রান করে এবং কোনও দীর্ঘ চলমান প্রক্রিয়াটি UI কে লক করবে, এটি প্রতিক্রিয়াশীল করবে। অতিরিক্তভাবে, জাভাস্ক্রিপ্টের জন্য কার্যকর সময়টির উপরে একটি উচ্চ সীমা রয়েছে এবং ব্রাউজার ব্যবহারকারীকে জিজ্ঞাসা করবে কিনা তা কার্যকর করতে হবে কিনা।

এই সব সত্যিই খারাপ ব্যবহারকারীর অভিজ্ঞতা। সবকিছু ঠিকঠাক কাজ করছে কিনা তা ব্যবহারকারীরা বলতে পারবে না। উপরন্তু, একটি ধীর সংযোগ ব্যবহারকারীদের জন্য প্রভাব খারাপ হবে।

নিচের দিকে আমরা তিনটি ভিন্ন সমাধানের দিকে নজর দেব যা একে অপরের শীর্ষে রয়েছে।

  • Async async/await (ES2017 +, আপনি একটি ট্রান্সপারার বা পুনর্নবীকরণকারী ব্যবহার করলে পুরানো ব্রাউজারে উপলব্ধ) সঙ্গে প্রতিশ্রুতি
  • Callbacks (নোড জনপ্রিয়)
  • then() প্রতিশ্রুতিগুলি then() (ES2015 +, পুরানো ব্রাউজারে উপলব্ধ থাকলে আপনি অনেক প্রতিশ্রুতি লাইব্রেরি ব্যবহার করেন)

সমস্ত তিন বর্তমান ব্রাউজারে উপলব্ধ, এবং নোড 7+।

ES2017 +: Async async/await সঙ্গে প্রতিশ্রুতি

2017 সালে প্রকাশিত ECMAScript সংস্করণটি অ্যাসিঙ্ক্রোনাস ফাংশনগুলির জন্য সিন্ট্যাক্স স্তরের সহায়তা সরবরাহ করেছিলasync এবং await করতে, আপনি একটি "সমলয় শৈলী" এ অ্যাসিঙ্ক্রোনাস লিখতে পারেন। কোড এখনও অ্যাসিঙ্ক্রোনাস, কিন্তু এটি সহজ / পড়তে সহজ।

async/await প্রতিশ্রুতি শীর্ষে builds: একটি async ফাংশন সবসময় একটি প্রতিশ্রুতি প্রদান করে। প্রতিশ্রুতি প্রত্যাখ্যান করা হয় তাহলে প্রতিশ্রুতি "unwraps" এবং উভয় প্রতিশ্রুতি সঙ্গে প্রতিশ্রুতি সমাধান করা হয়েছে বা একটি ত্রুটি ছোঁড়ে ফলে ফলাফল।

গুরুত্বপূর্ণ: আপনি শুধুমাত্র একটি async ফাংশনের ভিতরে await করতে পারেন। এর মানে হল যে খুব শীর্ষ স্তরে, আপনি এখনও প্রতিশ্রুতি সঙ্গে সরাসরি কাজ করতে হবে।

আপনি async/await সম্পর্কে আরও পড়তে এবং MDN এ await করতে পারেন।

এখানে একটি উদাহরণ যা উপরের দের উপরে তৈরি করে:

// Using 'superagent' which will return a promise.
var superagent = require('superagent')

// This is isn't declared as `async` because it already returns a promise
function delay() {
  // `delay` returns a promise
  return new Promise(function(resolve, reject) {
    // Only `delay` is able to resolve or reject the promise
    setTimeout(function() {
      resolve(42); // After 3 seconds, resolve the promise with value 42
    }, 3000);
  });
}


async function getAllBooks() {
  try {
    // GET a list of book IDs of the current user
    var bookIDs = await superagent.get('/user/books');
    // wait for 3 seconds (just for the sake of this example)
    await delay();
    // GET information about each book
    return await superagent.get('/books/ids='+JSON.stringify(bookIDs));
  } catch(error) {
    // If any of the awaited promises was rejected, this catch block
    // would catch the rejection reason
    return null;
  }
}

// Async functions always return a promise
getAllBooks()
  .then(function(books) {
    console.log(books);
  });

বর্তমান browser এবং node সংস্করণ async/await সমর্থন। আপনি regenerator সাহায্যে আপনার কোডটি ES5 এ রূপান্তর করে পুরানো পরিবেশগুলি সমর্থন করতে পারেন (বা বাজেল ব্যবহারকারী সরঞ্জামগুলি যেমন Babel )।

ফাংশন callbacks গ্রহণ করা যাক

একটি কলব্যাক সহজভাবে অন্য ফাংশন পাস একটি ফাংশন। অন্য যে ফাংশনটি প্রস্তুত হয়ে গেলে ফাংশনটি কল করতে পারে। একটি অ্যাসিঙ্ক্রোনাস প্রক্রিয়া প্রসঙ্গে, যখনই অ্যাসিঙ্ক্রোনাস প্রক্রিয়া সম্পন্ন হয় তখন কলব্যাকটি কল করা হবে। সাধারণত, ফলাফল কলব্যাক পাস করা হয়।

প্রশ্নটির উদাহরণে, আপনি foo কে একটি কলব্যাক গ্রহণ করতে এবং success কলব্যাক হিসাবে এটি ব্যবহার করতে পারেন। সুতরাং এই

var result = foo();
// Code that depends on 'result'

হয়ে

foo(function(result) {
    // Code that depends on 'result'
});

এখানে আমরা "ইনলাইন" ফাংশন সংজ্ঞায়িত করেছি কিন্তু আপনি কোন ফাংশন রেফারেন্স পাস করতে পারেন:

function myCallback(result) {
    // Code that depends on 'result'
}

foo(myCallback);

foo নিজেই অনুসরণ হিসাবে সংজ্ঞায়িত করা হয়:

function foo(callback) {
    $.ajax({
        // ...
        success: callback
    });
}

callback আমরা ফ্যাকাশে পাস ফাংশন উল্লেখ করব যখন আমরা এটি কল এবং আমরা কেবল success এটি পাস। আমি একবার অ্যাজ্যাক্সের অনুরোধ সফল হলে, $.ajax callback কল করবে এবং callback প্রতিক্রিয়াটি প্রেরণ করবে (যা result সাথে উল্লেখ করা যেতে পারে, যেহেতু আমরা কলব্যাক সংজ্ঞায়িত করেছি)।

আপনি কলব্যাকটি পাস করার আগে প্রতিক্রিয়া প্রক্রিয়া করতে পারেন:

function foo(callback) {
    $.ajax({
        // ...
        success: function(response) {
            // For example, filter the response
            callback(filtered_response);
        }
    });
}

এটা মনে হতে পারে কলব্যাক ব্যবহার করে কোড লিখতে সহজ। সব পরে, ব্রাউজারে জাভাস্ক্রিপ্ট ব্যাপকভাবে ইভেন্ট চালিত (DOM ঘটনা)। অ্যাজ্যাক্স প্রতিক্রিয়া প্রাপ্তি একটি ইভেন্ট ছাড়া অন্য কিছুই নয়।
তৃতীয় পক্ষের কোডের সাথে কাজ করার সময় অসুবিধাগুলি উঠতে পারে, তবে অ্যাপ্লিকেশন প্রবাহের মাধ্যমে চিন্তা করে বেশিরভাগ সমস্যার সমাধান করা যেতে পারে।

ES2015 +: then() সঙ্গে প্রতিশ্রুতি then()

then() এ ECMAScript 6 (ES2015) এর একটি নতুন বৈশিষ্ট্য, তবে এটিতে ইতিমধ্যে ভাল ব্রাউজার সমর্থন রয়েছে । এমন অনেক লাইব্রেরি রয়েছে যা স্ট্যান্ডার্ড Promises API বাস্তবায়ন করে এবং অ্যাসিনক্রোনাস ফাংশনগুলির (যেমন bluebird ) ব্যবহার এবং সুরক্ষার bluebird অতিরিক্ত পদ্ধতি সরবরাহ করে।

প্রতিশ্রুতি ভবিষ্যতের মান জন্য পাত্রে। যখন প্রতিশ্রুতিটি মানটি গ্রহণ করে (এটি সমাধান করা হয় ) বা যখন এটি বাতিল করা হয় ( প্রত্যাখ্যাত ), এটি তার সমস্ত "শ্রোতা" কে এই মানটি অ্যাক্সেস করতে চায় তা সূচিত করে।

প্লেইন কলব্যাকের সুবিধাগুলি হল যে তারা আপনাকে আপনার কোডটি বাতিল করতে দেয় এবং তারা রচনা করতে সহজ হয়।

এখানে একটি প্রতিশ্রুতি ব্যবহার করার একটি সহজ উদাহরণ:

function delay() {
  // `delay` returns a promise
  return new Promise(function(resolve, reject) {
    // Only `delay` is able to resolve or reject the promise
    setTimeout(function() {
      resolve(42); // After 3 seconds, resolve the promise with value 42
    }, 3000);
  });
}

delay()
  .then(function(v) { // `delay` returns a promise
    console.log(v); // Log the value once it is resolved
  })
  .catch(function(v) {
    // Or do something else if it is rejected 
    // (it would not happen in this example, since `reject` is not called).
  });

আমাদের অ্যাজ্যাক্স কলটিতে প্রয়োগ করা হয়েছে আমরা এই ধরনের প্রতিশ্রুতি ব্যবহার করতে পারি:

function ajax(url) {
  return new Promise(function(resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.onload = function() {
      resolve(this.responseText);
    };
    xhr.onerror = reject;
    xhr.open('GET', url);
    xhr.send();
  });
}

ajax("/echo/json")
  .then(function(result) {
    // Code depending on result
  })
  .catch(function() {
    // An error occurred
  });

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

প্রতিশ্রুতি সম্পর্কে আরও তথ্য: HTML5 পাথর - জাভাস্ক্রিপ্ট প্রতিশ্রুতি

সাইড নোট: jQuery এর বিলম্বিত বস্তু

Deferred বস্তু প্রতিশ্রুতি jQuery এর কাস্টম বাস্তবায়ন হয় (প্রতিশ্রুতি API এ মানদন্ড আগে)। তারা প্রায় প্রতিশ্রুতি মত আচরণ কিন্তু সামান্য ভিন্ন API প্রকাশ।

JQuery এর প্রতিটি অজ্যাক্স পদ্ধতি ইতিমধ্যে একটি "স্থগিত বস্তু" (আসলে একটি বিলম্বিত বস্তুর একটি প্রতিশ্রুতি) প্রদান করে যা আপনি কেবল আপনার ফাংশন থেকে ফিরে আসতে পারেন:

function ajax() {
    return $.ajax(...);
}

ajax().done(function(result) {
    // Code depending on result
}).fail(function() {
    // An error occurred
});

সাইড নোট: Promise gotchas

মনে রাখবেন যে প্রতিশ্রুতি এবং বিলম্বিত বস্তু শুধুমাত্র ভবিষ্যতের মানের জন্য ধারক , তারা মানটি নিজেই নয়। উদাহরণস্বরূপ, ধরুন আপনার নিম্নলিখিত ছিল:

function checkPassword() {
    return $.ajax({
        url: '/password',
        data: {
            username: $('#username').val(),
            password: $('#password').val()
        },
        type: 'POST',
        dataType: 'json'
    });
}

if (checkPassword()) {
    // Tell the user they're logged in
}

এই কোডটি উপরের অ্যাসিঙ্ক্রনি সমস্যাগুলিকে ভুল বোঝায়। বিশেষ করে, $.ajax() আপনার সার্ভারে '/ পাসওয়ার্ড' পৃষ্ঠাটি পরীক্ষা করে কোডটি নিশ্চিহ্ন করে না - এটি সার্ভারে একটি অনুরোধ পাঠায় এবং এটি অপেক্ষা করার সময়, অবিলম্বে একটি jQuery অ্যাজ্যাক্স ডিফার্ড অবজেক্ট প্রদান করে, প্রতিক্রিয়া নয় সার্ভার. এর অর্থ হল if বিবৃতিটি সর্বদা এই ডিফার্ড অবজেক্টটি পেতে চলেছে, এটি true হিসাবে বিবেচিত হবে এবং ব্যবহারকারীর লগ ইন থাকা উচিত। ভাল না।

কিন্তু ফিক্স সহজ:

checkPassword()
.done(function(r) {
    if (r) {
        // Tell the user they're logged in
    } else {
        // Tell the user their password was bad
    }
})
.fail(function(x) {
    // Tell the user something bad happened
});

সুপারিশ করা হয় না: সিঙ্ক্রোনাস "অজ্যাক্স" কল

আমি যেমন উল্লেখ করেছি, কিছু (!) অ্যাসিঙ্ক্রোনাস ক্রিয়াকলাপগুলির সমকক্ষ সমতুল্য রয়েছে। আমি তাদের ব্যবহারকে সমর্থন করি না, কিন্তু সম্পূর্ণতার জন্য, এখানে আপনি একটি সিঙ্ক্রোনাস কলটি সঞ্চালন করবেন:

JQuery ছাড়া

যদি আপনি সরাসরি একটি XMLHTTPRequest বস্তু ব্যবহার করেন, তবে XMLHTTPRequest করতে তৃতীয় যুক্তি হিসাবে false পাস করুন।

jQuery এর

আপনি যদি jQuery ব্যবহার করেন, আপনি async বিকল্পটি false সেট করতে পারেন। উল্লেখ্য যে এই বিকল্পটি jQuery 1.8 থেকে অব্যবহৃত। আপনি তখনও একটি success কলব্যাক ব্যবহার করতে পারেন অথবা jqXHR অবজেক্টের responseText প্রসঙ্গের অ্যাক্সেসটি অ্যাক্সেস করতে পারেন:

function foo() {
    var jqXHR = $.ajax({
        //...
        async: false
    });
    return jqXHR.responseText;
}

আপনি যদি $.getJSON , $.getJSON , ইত্যাদির মতো অন্য কোনও jQuery এ্যাজ্যাক্স পদ্ধতি ব্যবহার করেন তবে আপনাকে এটি $.ajax পরিবর্তন করতে হবে (আপনি শুধুমাত্র $.ajax কনফিগারেশন পরামিতিগুলি পাস করতে পারবেন)।

হেড আপ! একটি সমলয় JSONP অনুরোধ করা সম্ভব নয়। JSONP এর খুব প্রকৃতির দ্বারা সর্বদা অ্যাসিঙ্ক্রোনাস (এমনকি এই বিকল্পটি বিবেচনা না করার আরেকটি কারণ)।


জেএস একটি থ্রেডেড।

ব্রাউজার তিনটি ভাগে বিভক্ত করা যাবে:

1) ইভেন্ট লুপ

2) ওয়েব এপিআই

3) ইভেন্ট সারি

ইভেন্ট লুপটি চিরকালের জন্য চলছে যেমন অসীম লুপ। ইভেন্ট সারি যেখানে আপনার সমস্ত ফাংশন কিছু ইভেন্টে push করা হয় (উদাহরণ: ক্লিক করুন) এটি একটি সারির বাহিরে এক দ্বারা এবং ইভেন্ট লুপে ঢোকানো যা এই ফাংশনটি কার্যকর করে এবং এটি নিজে তৈরি করে প্রথমটির পরে প্রথমটির জন্য কার্যকর করা হয়। এর অর্থ হল একটি ফাংশন কার্যকর হওয়া পর্যন্ত এটি লুপে ফাংশন পর্যন্ত ইভেন্ট লুপে কার্যকর হয় না।

এখন আমাদের মনে হয় আমরা একটি সারিতে দুইটি ফাংশনকে সরিয়ে দিয়েছি সার্ভার থেকে একটি ডেটা পাওয়ার জন্য এবং অন্যটি সেই তথ্যটি ব্যবহার করে। আমরা serverRequest () ফাংশনটি প্রথমে সারিতে ব্যবহার করলাম তারপর usetilata () ফাংশনটি। serverRequest ফাংশন ইভেন্ট লুপে যায় এবং সার্ভারে একটি কল করে কারণ আমরা জানি না সার্ভার থেকে ডেটা পেতে কত সময় লাগবে তাই এই প্রক্রিয়াটি সময় লাগবে বলে আশা করা হচ্ছে এবং তাই আমরা আমাদের ইভেন্ট লুপ ব্যস্ত করে আমাদের পৃষ্ঠাটি ঝুলিয়ে রাখি, যেখানে ওয়েব এপিআই ভূমিকা পালন করে, এটি ইভেন্ট লুপ থেকে এবং ফাংশনটি সার্ভার তৈরি ইভেন্ট লুপ মুক্ত করে নিয়ে যায় যাতে আমরা সারি থেকে পরবর্তী ফাংশনটি চালাতে পারি। পরবর্তী ফাংশনটি সারিতে ব্যবহার করা হয় () যা লুপে যায় তবে কোন তথ্য পাওয়া যায় না বর্জ্য এবং পরবর্তী ফাংশনের নির্বাহটি সারির শেষ পর্যন্ত চলতে থাকে। (এইটিকে অ্যাসিনক কলিং বলা হয় অর্থাত্ আমরা তথ্য পেতে না পারলে অন্য কিছু করতে পারি)

ধরুন আমাদের serverRequest () ফাংশনটি একটি কোডের একটি বিনিময় বিবৃতি ছিল, যখন আমরা সার্ভার ওয়েব API থেকে ডেটা ফিরে পাব তখন এটি সারির শেষে সারিতে চাপিয়ে দেবে। সারির শেষে এটি ধাক্কা দেওয়া হিসাবে আমরা তার ডেটা ব্যবহার করতে পারছি না কারণ এই তথ্যটি ব্যবহার করতে আমাদের সারিতে কোনও ফাংশন বাকি নেই। সুতরাং Async কল থেকে কিছু ফেরত পাওয়া সম্ভব নয়।

সুতরাং এই সমাধান callback বা প্রতিশ্রুতি

এখানে একটি উত্তর থেকে একটি চিত্র, সঠিকভাবে কলব্যাক ব্যবহার ব্যাখ্যা করে ... আমরা কলিং সার্ভার ফাংশন করতে আমাদের ফাংশন (সার্ভার থেকে ফেরত তথ্য ব্যবহার করে ফাংশন) দিতে।

 function doAjax(callbackFunc, method, url) {
  var xmlHttpReq = new XMLHttpRequest();
  xmlHttpReq.open(method, url);
  xmlHttpReq.onreadystatechange = function() {

      if (xmlHttpReq.readyState == 4 && xmlHttpReq.status == 200) {
        callbackFunc(xmlHttpReq.responseText);
      }


  }
  xmlHttpReq.send(null);

}

আমার কোড হিসাবে এটি বলা হয়

function loadMyJson(categoryValue){
  if(categoryValue==="veg")
  doAjax(print,"GET","http://localhost:3004/vegetables");
  else if(categoryValue==="fruits")
  doAjax(print,"GET","http://localhost:3004/fruits");
  else 
  console.log("Data not found");
}

অ্যাসাইন কল করার জন্য ECMA (2016/17) এ নতুন পদ্ধতিগুলির জন্য এখানে পড়ুন (@ ফেলিক্স ক্লিং উত্তর উপরে) https://.com/a/14220323/7579856


আপনি যদি আপনার কোডে jQuery ব্যবহার না করেন তবে এই উত্তরটি আপনার জন্য

আপনার কোডটি লাইন বরাবর কিছু হওয়া উচিত:

function foo() {
    var httpRequest = new XMLHttpRequest();
    httpRequest.open('GET', "/echo/json");
    httpRequest.send();
    return httpRequest.responseText;
}

var result = foo(); // always ends up being 'undefined'

Felix Kling AJAX এর জন্য jQuery ব্যবহার করে লোকেদের জন্য একটি উত্তর লিখে একটি সূক্ষ্ম কাজ করেছেন, আমি যারা নেই তাদের জন্য বিকল্প প্রদান করার সিদ্ধান্ত নিয়েছি।

( নোট, যারা নতুন fetch API, কৌণিক বা প্রতিশ্রুতি ব্যবহার করে আমি নীচের একটি উত্তর যোগ করেছি )

আপনি সম্মুখীন কি

এটি অন্য উত্তর থেকে "সমস্যার ব্যাখ্যা" এর একটি সংক্ষিপ্ত সারাংশ, যদি আপনি এটি পড়ার পরে নিশ্চিত না হন তবে তা পড়ুন।

এএইচএক্স এ একটি অ্যাসিঙ্ক্রোনাস জন্য দাঁড়িয়েছে। এর মানে হল অনুরোধ পাঠানো (অথবা প্রতিক্রিয়া গ্রহণ করা) স্বাভাবিক মৃত্যুদন্ড প্রবাহের বাইরে নেওয়া হয়। আপনার উদাহরণে, অবিলম্বে ফেরত .send এবং পরবর্তী বিবৃতি, return result; , success কলব্যাক এমনকি আপনি বলা হয় হিসাবে পাস ফাংশন আগে মৃত্যুদন্ড কার্যকর করা হয়।

এর মানে হল আপনি যখন ফিরে আসছেন, আপনি যে শ্রোতাটি সংজ্ঞায়িত করেছেন তা এখনও কার্যকর হয়নি, যার অর্থ আপনি যে মানটি ফিরেছেন তা সংজ্ঞায়িত করা হয়নি।

এখানে একটি সহজ উপমা

function getFive(){ 
    var a;
    setTimeout(function(){
         a=5;
    },10);
    return a;
}

(Fiddle)

a ফেরত মান undefined কারণ a=5 অংশ এখনো নির্বাহ করা হয় নি। AJAX এভাবে কাজ করে, সার্ভারটিকে আপনার ব্রাউজারকে যে মানটি বলে তা জানানোর সুযোগ পাওয়ার আগে আপনি মানটি ফেরত দিচ্ছেন।

এই সমস্যাটির একটি সম্ভাব্য সমাধান পুনরায় সক্রিয়ভাবে কোড করা, আপনার প্রোগ্রামটি গণনা সম্পন্ন করার সময় কী করা উচিত তা বলছে।

function onComplete(a){ // When the code completes, do this
    alert(a);
}

function getFive(whenDone){ 
    var a;
    setTimeout(function(){
         a=5;
         whenDone(a);
    },10);
}

এই CPS বলা হয়। মূলত, আমরা পেয়ে যাচ্ছি, এটি সম্পন্ন করার জন্য একটি পদক্ষেপ কার্যকর করুন, আমরা আমাদের কোডটি বলছি যখন একটি ইভেন্ট সম্পন্ন হওয়ার সময় কীভাবে প্রতিক্রিয়া জানাতে হবে (যেমন আমাদের AJAX কল, অথবা এই ক্ষেত্রে টাইমআউট)।

ব্যবহার হবে:

getFive(onComplete);

যা পর্দায় "5" সতর্কতা অবলম্বন করা উচিত। (Fiddle)

সম্ভাব্য সমাধান

মূলত দুটি সমাধান কীভাবে সমাধান করতে হয়:

  1. AJAX কল সমলয় করুন (এটি SJAX কল করতে দেয়)।
  2. Callbacks সঙ্গে সঠিকভাবে কাজ করার জন্য আপনার কোড পুনর্নির্মাণ।

1. সমলয় AJAX - এটা করবেন না !!

সিঙ্ক্রোনাস AJAX হিসাবে, এটি করবেন না! ফেলিক্সের উত্তরটি কেন একটি খারাপ ধারণা সম্পর্কে কিছু বাধ্যতামূলক আর্গুমেন্ট তুলে ধরে। এটির সমষ্টিগতভাবে, এটি ব্যবহারকারীর ব্রাউজারটি স্থির করবে যতক্ষণ না সার্ভার প্রতিক্রিয়াটি ফেরত দেয় এবং খুব খারাপ ব্যবহারকারীর অভিজ্ঞতা তৈরি করে। এখানে এমডিএন থেকে নেওয়া আরেকটি সংক্ষিপ্ত সারসংক্ষেপ কেন:

XMLHttpRequest উভয় সমলয় এবং অ্যাসিঙ্ক্রোনাস যোগাযোগ সমর্থন করে। সাধারণভাবে, তবে, কর্মক্ষম কারণে সিঙ্ক্রোনাস অনুরোধগুলির জন্য অ্যাসিঙ্ক্রোনাস অনুরোধগুলি অগ্রাধিকার দেওয়া উচিত।

সংক্ষেপে, সিঙ্ক্রোনাস অনুরোধগুলি কোড কার্যকর করা বন্ধ করে দেয় ... ... এর ফলে গুরুতর সমস্যা হতে পারে ...

যদি আপনি এটি করতে চান, আপনি একটি পতাকা পাস করতে পারেন: এখানে কিভাবে:

var request = new XMLHttpRequest();
request.open('GET', 'yourURL', false);  // `false` makes the request synchronous
request.send(null);

if (request.status === 200) {// That's HTTP for 'ok'
  console.log(request.responseText);
}

2. কোড পুনঃনির্মাণ

আপনার ফাংশন একটি কলব্যাক গ্রহণ করা যাক। উদাহরণ কোড foo একটি callback গ্রহণ করতে পারেন। আমরা foo সম্পন্ন যখন প্রতিক্রিয়া কিভাবে আমাদের কোড বলা হবে।

তাই:

var result = foo();
// code that depends on `result` goes here

হয়ে:

foo(function(result) {
    // code that depends on `result`
});

এখানে আমরা একটি বেনামী ফাংশনটি পাস করেছি, কিন্তু আমরা সহজেই একটি বিদ্যমান ফাংশনের একটি রেফারেন্স পাস করতে পারছি, এটি এটির মত দেখাচ্ছে:

function myHandler(result) {
    // code that depends on `result`
}
foo(myHandler);

এই ধরণের কলব্যাক ডিজাইন কীভাবে সম্পন্ন হয় সে সম্পর্কে আরো বিস্তারিত জানার জন্য, ফেলিক্সের উত্তর পরীক্ষা করুন।

এখন, এর অনুযায়ী কাজ করতে Foo নিজেই সংজ্ঞায়িত করা যাক

function foo(callback) {
    var httpRequest = new XMLHttpRequest();
    httpRequest.onload = function(){ // when the request is loaded
       callback(httpRequest.responseText);// we're calling our method
    };
    httpRequest.open('GET', "/echo/json");
    httpRequest.send();
}

(fiddle)

আমরা এখন আমাদের foo ফাংশনটি কার্যকর করেছি যখন AJAX সফলভাবে সম্পন্ন হয় তখন চালানোর জন্য একটি পদক্ষেপ গ্রহণ করা হয়, প্রতিক্রিয়া স্থিতিটি 200 না হয় এবং সে অনুযায়ী কাজ করে (ব্যর্থ হ্যান্ডলার এবং এটিকে তৈরি করুন) পরীক্ষা করে আমরা আরও প্রসারিত করতে পারি। কার্যকরীভাবে আমাদের সমস্যা সমাধান।

যদি আপনি এখনও এমডএন এ AJAX শুরু করার নির্দেশিকাটি পড়তে বোঝার সময়টি বুঝতে পারছেন।


2017 উত্তর: আপনি এখন যা করতে চান তা প্রতিটি বর্তমান ব্রাউজার এবং নোডের সাথে ঠিক করতে পারেন

এটি বেশ সহজ:

  • একটি প্রতিশ্রুতি ফিরে
  • await ব্যবহার করুন , যা জাভাস্ক্রিপ্টকে একটি মানতে সমাধান করার প্রতিশ্রুতির জন্য অপেক্ষা করবে (HTTP প্রতিক্রিয়া মত)
  • যোগ async/await পিতা বা মাতা ফাংশন শব্দ

এখানে আপনার কোডের একটি কার্যকর সংস্করণ রয়েছে:

(async function(){

var response = await superagent.get('...')
console.log(response)

})()

অপেক্ষা সমস্ত বর্তমান ব্রাউজার এবং নোড সমর্থিত 8


এখানে অ্যাসিঙ্ক্রোনাস অনুরোধগুলির সাথে কাজ করার কিছু পদ্ধতি রয়েছে:

  1. then()
  2. Q - জাভাস্ক্রিপ্ট জন্য একটি প্রতিশ্রুতি লাইব্রেরি
  3. এ + Promises.js
  4. jQuery বিলম্বিত
  5. XMLHttpRequest API
  6. কলব্যাক ধারণা ব্যবহার করে - প্রথম উত্তর বাস্তবায়ন হিসাবে

উদাহরণ: একাধিক অনুরোধের সাথে কাজ করার জন্য jQuery বিলম্বিত বাস্তবায়ন

var App = App || {};

App = {
    getDataFromServer: function(){

      var self = this,
                 deferred = $.Deferred(),
                 requests = [];

      requests.push($.getJSON('request/ajax/url/1'));
      requests.push($.getJSON('request/ajax/url/2'));

      $.when.apply(jQuery, requests).done(function(xhrResponse) {
        return deferred.resolve(xhrResponse.result);
      });
      return deferred;
    },

    init: function(){

        this.getDataFromServer().done(_.bind(function(resp1, resp2) {

           // Do the operations which you wanted to do when you
           // get a response from Ajax, for example, log response.
        }, this));
    }
};
App.init();


XMLHttpRequest 2 (প্রথম সবই বেঞ্জামিন গ্রুয়েনবাম এবং ফেলিক্স ক্লিংয়ের উত্তরগুলি পড়েছেন)

আপনি যদি jQuery ব্যবহার না করেন এবং একটি দুর্দান্ত ছোট XMLHttpRequest 2 চান যা আধুনিক ব্রাউজারে এবং মোবাইল ব্রাউজারে কাজ করে তবে আমি এটি ব্যবহার করার পরামর্শ দিই:

function ajax(a, b, c){ // URL, callback, just a placeholder
  c = new XMLHttpRequest;
  c.open('GET', a);
  c.onload = b;
  c.send()
}

আপনি দেখতে পারেন:

  1. এটি তালিকাভুক্ত অন্যান্য সমস্ত ফাংশন চেয়ে সংক্ষিপ্ত।
  2. কলব্যাক সরাসরি সেট করা হয় (তাই অতিরিক্ত অতিরিক্ত অপ্রয়োজনীয় বন্ধ)।
  3. এটি নতুন অনলোড ব্যবহার করে (তাই আপনাকে প্রস্তুত স্ট্যাটাস এবং স্থিতির জন্য চেক করতে হবে না)
  4. এমন কিছু অন্যান্য পরিস্থিতি রয়েছে যা আমি মনে রাখি না যে XMLHttpRequest 1 বিরক্তিকর করে।

এই Ajax কলটির প্রতিক্রিয়া পেতে দুটি উপায় রয়েছে (তিনটি XMLHttpRequest var নাম ব্যবহার করে):

সহজতম:

this.response

অথবা কিছু কারণে যদি আপনি একটি ক্লাসে কলব্যাকটি বাঁধেন:

e.target.response

উদাহরণ:

function callback(e){
  console.log(this.response);
}
ajax('URL', callback);

অথবা (উপরের একটি ভাল বেনামী ফাংশন সবসময় একটি সমস্যা):

ajax('URL', function(e){console.log(this.response)});

কিছুই সহজ।

এখন কিছু লোক সম্ভবত বলে দেবে যে এটি ইতিমধ্যেই স্ট্যাটাস বিনিময় বা এমনকি XMLHttpRequest পরিবর্তনশীল নাম ব্যবহার করা ভাল। ওইটা ভুল.

XMLHttpRequest উন্নত বৈশিষ্ট্য পরীক্ষা করে দেখুন

এটা সব * আধুনিক ব্রাউজারে সমর্থিত। এবং XMLHttpRequest 2 বিদ্যমান থেকে আমি এই পদ্ধতিটি ব্যবহার করছি হিসাবে আমি নিশ্চিত করতে পারি। আমি ব্যবহার সব ব্রাউজারে কোন ধরনের সমস্যা ছিল না।

onreadystatechange শুধুমাত্র দরকারী যদি আপনি রাষ্ট্র 2 উপর হেডার পেতে চান।

XMLHttpRequest ভেরিয়েবল নামটি ব্যবহার করা আরেকটি বড় ত্রুটি যা আপনাকে এটি লোড না থাকলে ওল্ড / ওরিস্টস্টেচচেন বন্ধের ভিতরে কলব্যাকটি চালানো দরকার।

এখন যদি আপনি পোস্ট এবং ফরমডাটা ব্যবহার করে আরো জটিল কিছু চান তবে আপনি সহজেই এই ফাংশনটি প্রসারিত করতে পারেন:

function x(a, b, e, d, c){ // URL, callback, method, formdata or {key:val},placeholder
  c = new XMLHttpRequest;
  c.open(e||'get', a);
  c.onload = b;
  c.send(d||null)
}

আবার ... এটি একটি খুব ছোট ফাংশন, কিন্তু এটি পেতে এবং পোস্ট।

ব্যবহারের উদাহরণ:

x(url, callback); // By default it's get so no need to set
x(url, callback, 'post', {'key': 'val'}); // No need to set post data

অথবা একটি সম্পূর্ণ ফর্ম উপাদান ( document.getElementsByTagName('form')[0] পাস করুন document.getElementsByTagName('form')[0] ):

var fd = new FormData(form);
x(url, callback, 'post', fd);

অথবা কিছু কাস্টম মান সেট করুন:

var fd = new FormData();
fd.append('key', 'val')
x(url, callback, 'post', fd);

আপনি দেখতে পারেন যে আমি সিঙ্ক বাস্তবায়ন করিনি ... এটি একটি খারাপ জিনিস।

যে বলেছে ... কেন সহজ উপায় না?

মন্তব্য হিসাবে উল্লিখিত ত্রুটি & সম synchronous ব্যবহার উত্তর সম্পূর্ণ বিন্দু বিরতি করে। সঠিক ভাবে এ্যাজাক্স ব্যবহার করার জন্য একটি চমৎকার সংক্ষিপ্ত উপায় কোনটি?

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

function x(a, b, e, d, c){ // URL, callback, method, formdata or {key:val}, placeholder
  c = new XMLHttpRequest;
  c.open(e||'get', a);
  c.onload = b;
  c.onerror = error;
  c.send(d||null)
}

function error(e){
  console.log('--Error--', this.type);
  console.log('this: ', this);
  console.log('Event: ', e)
}
function displayAjax(e){
  console.log(e, this);
}
x('WRONGURL', displayAjax);

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

কিন্তু সত্যিই একটি ত্রুটি খুঁজে বের করতে একমাত্র উপায় একটি ভুল URL লিখতে হয়, যার ক্ষেত্রে প্রতিটি ব্রাউজার একটি ত্রুটি ছুঁড়ে ফেলে।

ত্রুটি হ্যান্ডলারগুলি যদি আপনি কাস্টম হেডার সেট করেন তবে প্রতিক্রিয়া সেট করুন, অ্যারে বাফার বা টাইপ করুন যা কিছু টাইপ করুন।

এমনকি যদি আপনি 'POSTAPAPAP' পদ্ধতি হিসাবে পাস করেন তবে এটি একটি ত্রুটি নিক্ষেপ করবে না।

এমনকি যদি আপনি ফর্মডটা হিসাবে 'fdggdgilfdghfldj' পাস করেন তবে এটি একটি ত্রুটি নিক্ষেপ করবে না।

প্রথম ক্ষেত্রে ত্রুটিটি this.statusText displayAjax() -এর ভিতরে রয়েছে। this.statusText হিসাবে Method not Allowed

দ্বিতীয় ক্ষেত্রে, এটি কেবল কাজ করে। সঠিক পোস্ট ডেটা পাস করলে আপনাকে সার্ভারের পাশে চেক করতে হবে।

ক্রস ডোমেইন অনুমোদিত স্বয়ংক্রিয়ভাবে ত্রুটি ছোঁড়ে।

ত্রুটি প্রতিক্রিয়া, কোন ত্রুটি কোড আছে।

শুধুমাত্র এই this.type যা ত্রুটি সেট করা হয়।

যদি ত্রুটিগুলির উপর সম্পূর্ণ নিয়ন্ত্রণ না থাকে তবে কেন একটি ত্রুটি হ্যান্ডলার যুক্ত করবেন? বেশিরভাগ ত্রুটি কলব্যাক ফাংশন displayAjax() মধ্যে এটিকে ফেরত displayAjax()

সুতরাং: যদি আপনি সঠিকভাবে URL টি অনুলিপি করতে এবং পেস্ট করতে সক্ষম হন তবে ত্রুটির চেকগুলির কোন প্রয়োজন নেই। ;)

পিএসঃ প্রথম পরীক্ষা হিসাবে আমি এক্স ('এক্স', ডিসপ্লেআজ্যাক্স) লিখেছিলাম ..., এবং এটি সম্পূর্ণ প্রতিক্রিয়া পেয়েছে ... ??? তাই আমি যেখানে এইচটিএমএল অবস্থিত ফোল্ডারে চেক করেছি, এবং 'x.xml' নামে একটি ফাইল ছিল। তাই যদি আপনি XMLHttpRequest 2 ফাইলটি এক্সটেনশানটি ভুলে যান তবে এটি খুঁজে পাবে । আমি lol'd

সমলয় একটি ফাইল পড়ুন

যে না।

আপনি কিছু সময়ের জন্য ব্রাউজারকে ব্লক করতে চাইলে একটি সুন্দর বড় txt ফাইল সমলয় হয়।

function omg(a, c){ // URL
  c = new XMLHttpRequest;
  c.open('GET', a, true);
  c.send();
  return c; // Or c.response
}

এখন আপনি করতে পারেন

 var res = omg('thisIsGonnaBlockThePage.txt');

অ-সমান্তরাল ভাবে এটি করার অন্য কোন উপায় নেই। (হ্যাঁ, সেটটাইম লুপ দিয়ে ... কিন্তু গুরুত্ব সহকারে?)

আরেকটি বিন্দু ... যদি আপনি API গুলির সাথে কাজ করেন বা কেবলমাত্র আপনার তালিকাগুলির ফাইলগুলির মালিক হন বা আপনি যেকোন অনুরোধের জন্য সর্বদা বিভিন্ন ফাংশন ব্যবহার করেন ...

শুধুমাত্র যদি আপনার এমন একটি পৃষ্ঠা থাকে যেখানে আপনি সর্বদা একই এক্সএমএল / JSON লোড করেন বা আপনার যা শুধুমাত্র একটি ফাংশন প্রয়োজন। যে ক্ষেত্রে, একটু অ্যাজাক্স ফাংশন সংশোধন এবং আপনার বিশেষ ফাংশন সঙ্গে খ প্রতিস্থাপন।

উপরে ফাংশন মৌলিক ব্যবহার জন্য হয়।

যদি আপনি ফাংশন প্রসারিত করতে চান ...

হ্যা, তুমি পারো.

আমি অনেকগুলি API ব্যবহার করছি এবং প্রত্যেকটি HTML পৃষ্ঠাতে সংহত হওয়া প্রথম ফাংশনগুলির মধ্যে একটি হল এই উত্তরটিতে প্রথম অ্যাল্যাক্স ফাংশন, শুধুমাত্র GET সহ ...

কিন্তু আপনি XMLHttpRequest 2 এর সাথে প্রচুর পরিমাণে কাজ করতে পারেন:

আমি একটি ডাউনলোড ম্যানেজার (রেজিউম, ফাইলreader, ফাইল সিস্টেমের সাথে উভয় প্রান্তের রেঞ্জ ব্যবহার করে), ক্যানভাস ব্যবহার করে বিভিন্ন ইমেজ রিজাইজার রূপান্তরকারী, base64images সহ websql ডেটাবেসগুলি তৈরি করে এবং আরও অনেক কিছু ... তবে এই ক্ষেত্রে আপনাকে শুধুমাত্র সেই উদ্দেশ্যেই একটি ফাংশন তৈরি করতে হবে ... কখনও কখনও আপনি একটি blob, অ্যারে বাফার প্রয়োজন, আপনি হেডার সেট করতে পারেন, mimetype override এবং আরো অনেক কিছু আছে ...

কিন্তু এখানে প্রশ্ন হল কিভাবে অ্যাজ্যাক্স প্রতিক্রিয়াটি ফেরত দিতে হবে ... (আমি একটি সহজ উপায় যোগ করেছি।)


এর আগে গাছগুলো দেখার আগে প্রথমে বনটি দেখি।

এখানে প্রচুর বিবরণ সহ অনেক তথ্যপূর্ণ উত্তর আছে, আমি তাদের কোনও পুনরাবৃত্তি করব না। জাভাস্ক্রিপ্টে প্রোগ্রামিং করার চাবিকাঠি হচ্ছে সামগ্রিক মৃত্যুদণ্ডের প্রথম মানসিক মডেল

  1. আপনার এন্ট্রি পয়েন্ট (গুলি) একটি ইভেন্টের ফলাফল হিসাবে মৃত্যুদন্ড কার্যকর করা হয়। উদাহরণস্বরূপ, কোড সহ একটি স্ক্রিপ্ট ট্যাগ ব্রাউজারে লোড করা হয়। (তত্সহ, আপনাকে যদি ডোম উপাদানগুলিকে প্রথমে তৈরি করার প্রয়োজন হয় তবে আপনার কোডটি চালানোর জন্য পৃষ্ঠাটির প্রস্তুতির সাথে সংশ্লিষ্ট হওয়ার প্রয়োজন হতে পারে) ইত্যাদি।
  2. আপনার কোডটি সম্পন্ন করার জন্য কার্যকর হয় - তবে অনেকগুলি অ্যাসিঙ্ক্রোনাস কল এটি তৈরি করে - আপনার কোনও কলব্যাকগুলি এক্সিকিউটিভ না করে XHR অনুরোধ, সেট টাইমআউট, ডোম ইভেন্ট হ্যান্ডলার ইত্যাদি অন্তর্ভুক্ত করে। ইত্যাদি কলব্যাকগুলি কার্যকর হওয়ার জন্য অপেক্ষা করা প্রতিটিটি অপেক্ষা করছে, অপেক্ষা করছে তাদের পালা সব শেষ মৃত্যুদন্ড কার্যকর করা হয়েছে যে অন্যান্য ঘটনা পরে চালানো হবে।
  3. একটি এক্সএইচআর অনুরোধে প্রতিটি পৃথক কলব্যাক, একবার টাইমআউট বা ডম সেট ইভেন্ট একবার সঞ্চালিত হবে তারপর সম্পন্ন করতে হবে।

ভাল খবর হল যে আপনি এই বিন্দুটি ভালভাবে বুঝতে পারলে, আপনাকে কখনই জাতিগত অবস্থার বিষয়ে চিন্তা করতে হবে না। আপনি কীভাবে আপনার কোডটি সংগঠিত করতে চান তার প্রথম এবং সর্বাপেক্ষা গুরুত্বপূর্ণ বিষয় যা আপনি বিভিন্ন বিচ্ছিন্ন ইভেন্টগুলির প্রতিক্রিয়া হিসাবে এবং কীভাবে আপনি তাদের যৌক্তিক ক্রম অনুসারে থ্রেড করতে চান। আপনি প্রতিশ্রুতি বা উচ্চ স্তরের নতুন async ব্যবহার / শেষ করতে সরঞ্জাম হিসাবে অপেক্ষা করতে পারেন, অথবা আপনি আপনার নিজের রোল করতে পারেন।

কিন্তু আপনি কোন সমস্যা সমাধান করার জন্য কোনও কৌশলগত সরঞ্জামগুলি ব্যবহার করবেন না যতক্ষণ না আপনি প্রকৃত সমস্যা ডোমেনের সাথে আরামদায়ক। কখন চলতে হবে তা জানতে এই নির্ভরতাগুলির একটি মানচিত্র আঁকুন। এই সমস্ত কলব্যাকগুলির জন্য একটি অদ্ভুত পদ্ধতির চেষ্টা করা ঠিক আপনার ভাল পরিবেশন করা যাচ্ছে না।


সংক্ষিপ্ত উত্তর : ফাংশনটি ফেরার পরে কলটি foo()অবিচ্ছিন্নভাবে $ajax()সঞ্চালিত হওয়ার সময় আপনার পদ্ধতি অবিলম্বে ফেরত আসে । সমস্যাটি তখন ফিরে আসার পরে অ্যাসিনসি কল দ্বারা পুনরুদ্ধার হওয়া ফলাফলগুলি কীভাবে বা কোথায় সংরক্ষণ করতে হয়।

বিভিন্ন সমাধান এই থ্রেড দেওয়া হয়েছে। সম্ভবত সবচেয়ে সহজ উপায় হল foo()পদ্ধতিতে একটি বস্তু পাস করা , এবং অ্যাসাইন কলটি সমাপ্ত হওয়ার পরে সেই বস্তুর সদস্যকে ফলাফল সংরক্ষণ করা।

function foo(result) {
    $.ajax({
        url: '...',
        success: function(response) {
            result.response = response;   // Store the async result
        }
    });
}

var result = { response: null };   // Object to hold the async result
foo(result);                       // Returns before the async completes

মনে রাখবেন যে কলটি foo()এখনও দরকারী কিছু ফেরত দেবে না। যাইহোক, async কল ফলাফল এখন সংরক্ষণ করা হবে result.response


ES2017 ব্যবহার করে আপনার ফাংশন ঘোষণা হিসাবে এটি থাকা উচিত

async function foo() {
    var response = await $.ajax({url: '...'})
    return response;
}

এবং এই মত নির্বাহ।

(async function() {
    try {
        var result = await foo()
        console.log(result)
    } catch (e) {}
})()

বা প্রতিশ্রুতি সিনট্যাক্স

foo().then(response => {
    console.log(response)

}).catch(error => {
    console.log(error)

})

আপনি একটি রিমোট কল করতে এই কাস্টম লাইব্রেরি (প্রতিশ্রুতি ব্যবহার করে লেখা) ব্যবহার করতে পারেন।

function $http(apiConfig) {
    return new Promise(function (resolve, reject) {
        var client = new XMLHttpRequest();
        client.open(apiConfig.method, apiConfig.url);
        client.send();
        client.onload = function () {
            if (this.status >= 200 && this.status < 300) {
                // Performs the function "resolve" when this.status is equal to 2xx.
                // Your logic here.
                resolve(this.response);
            }
            else {
                // Performs the function "reject" when this.status is different than 2xx.
                reject(this.statusText);
            }
        };
        client.onerror = function () {
            reject(this.statusText);
        };
    });
}

সহজ ব্যবহার উদাহরণ:

$http({
    method: 'get',
    url: 'google.com'
}).then(function(response) {
    console.log(response);
}, function(error) {
    console.log(error)
});

নিম্নলিখিত উদাহরণ আমি লিখেছেন কিভাবে দেখায়

  • অ্যাসিঙ্ক্রোনাস HTTP কল হ্যান্ডেল;
  • প্রতিটি API কল থেকে প্রতিক্রিয়া জন্য অপেক্ষা করুন;
  • Promise প্যাটার্ন ব্যবহার করুন ;
  • একাধিক HTTP কল যোগ দিতে Promise.All প্যাটার্ন ব্যবহার করুন;

এই কাজ উদাহরণ স্ব অন্তর্নিহিত। এটি একটি সাধারণ অনুরোধ বস্তু সংজ্ঞায়িত করবে যা XMLHttpRequestকল করতে উইন্ডো অবজেক্ট ব্যবহার করে । এটি প্রতিশ্রুতি একটি গুচ্ছ জন্য সম্পন্ন করার জন্য একটি সহজ ফাংশন সংজ্ঞায়িত করা হবে।

প্রসঙ্গ। উদাহরণটি কোয়েরি স্ট্রিংগুলির একটি নির্দিষ্ট সেটের জন্য বস্তুর সন্ধান করার জন্য স্পটিফি ওয়েব API এপয়েন্ট পয়েন্ট playlistঅনুসন্ধান করছে:

[
 "search?type=playlist&q=%22doom%20metal%22",
 "search?type=playlist&q=Adele"
]

প্রতিটি আইটেমের জন্য, একটি নতুন প্রতিশ্রুতি একটি ব্লকে আগুন দেবে - ExecutionBlockফলাফলটি বিশ্লেষণ করে, ফলাফল অ্যারের উপর ভিত্তি করে প্রতিশ্রুতিগুলির একটি নতুন সেট নির্ধারিত করে, এটি Spotify userবস্তুর তালিকা এবং ExecutionProfileBlockঅ্যাসিঙ্ক্রোনাসেটের মধ্যে নতুন HTTP কলটি চালায় ।

আপনি একটি নেস্টেড প্রতিশ্রুতি কাঠামো দেখতে পারেন যা আপনাকে একাধিক এবং সম্পূর্ণ অ্যাসিঙ্ক্রোনাস নেস্টেড HTTP কলগুলি স্পন করতে দেয় এবং কলগুলির প্রতিটি উপসেট থেকে ফলাফলগুলিতে যোগ দেয় Promise.all

উল্লেখ্য সাম্প্রতিক স্পটিফ searchAPI গুলি অনুরোধ শিরোনামগুলিতে নির্দিষ্ট করার জন্য অ্যাক্সেস টোকেনের প্রয়োজন হবে:

-H "Authorization: Bearer {your access token}" 

তাই, নিম্নলিখিত শিরোনামটি চালানোর জন্য আপনাকে অনুরোধ শিরোনামগুলিতে আপনার অ্যাক্সেস টোকেনটি রাখতে হবে:

var spotifyAccessToken = "YourSpotifyAccessToken";
var console = {
    log: function(s) {
        document.getElementById("console").innerHTML += s + "<br/>"
    }
}

// Simple XMLHttpRequest
// based on https://davidwalsh.name/xmlhttprequest
SimpleRequest = {
    call: function(what, response) {
        var request;
        if (window.XMLHttpRequest) { // Mozilla, Safari, ...
            request = new XMLHttpRequest();
        } else if (window.ActiveXObject) { // Internet Explorer
            try {
                request = new ActiveXObject('Msxml2.XMLHTTP');
            }
            catch (e) {
                try {
                  request = new ActiveXObject('Microsoft.XMLHTTP');
                } catch (e) {}
            }
        }

        // State changes
        request.onreadystatechange = function() {
            if (request.readyState === 4) { // Done
                if (request.status === 200) { // Complete
                    response(request.responseText)
                }
                else
                    response();
            }
        }
        request.open('GET', what, true);
        request.setRequestHeader("Authorization", "Bearer " + spotifyAccessToken);
        request.send(null);
    }
}

//PromiseAll
var promiseAll = function(items, block, done, fail) {
    var self = this;
    var promises = [],
                   index = 0;
    items.forEach(function(item) {
        promises.push(function(item, i) {
            return new Promise(function(resolve, reject) {
                if (block) {
                    block.apply(this, [item, index, resolve, reject]);
                }
            });
        }(item, ++index))
    });
    Promise.all(promises).then(function AcceptHandler(results) {
        if (done) done(results);
    }, function ErrorHandler(error) {
        if (fail) fail(error);
    });
}; //promiseAll

// LP: deferred execution block
var ExecutionBlock = function(item, index, resolve, reject) {
    var url = "https://api.spotify.com/v1/"
    url += item;
    console.log( url )
    SimpleRequest.call(url, function(result) {
        if (result) {

            var profileUrls = JSON.parse(result).playlists.items.map(function(item, index) {
                return item.owner.href;
            })
            resolve(profileUrls);
        }
        else {
            reject(new Error("call error"));
        }
    })
}

arr = [
    "search?type=playlist&q=%22doom%20metal%22",
    "search?type=playlist&q=Adele"
]

promiseAll(arr, function(item, index, resolve, reject) {
    console.log("Making request [" + index + "]")
    ExecutionBlock(item, index, resolve, reject);
}, function(results) { // Aggregated results

    console.log("All profiles received " + results.length);
    //console.log(JSON.stringify(results[0], null, 2));

    ///// promiseall again

    var ExecutionProfileBlock = function(item, index, resolve, reject) {
        SimpleRequest.call(item, function(result) {
            if (result) {
                var obj = JSON.parse(result);
                resolve({
                    name: obj.display_name,
                    followers: obj.followers.total,
                    url: obj.href
                });
            } //result
        })
    } //ExecutionProfileBlock

    promiseAll(results[0], function(item, index, resolve, reject) {
        //console.log("Making request [" + index + "] " + item)
        ExecutionProfileBlock(item, index, resolve, reject);
    }, function(results) { // aggregated results
        console.log("All response received " + results.length);
        console.log(JSON.stringify(results, null, 2));
    }

    , function(error) { // Error
        console.log(error);
    })

    /////

  },
  function(error) { // Error
      console.log(error);
  });
<div id="console" />

আমি ব্যাপকভাবে here এই সমাধান আলোচনা করেছেন ।


প্রতিশ্রুতি এবং কলব্যাকগুলি বেশিরভাগ ক্ষেত্রেই সূক্ষ্ম কাজ করে, তবে এর মত কিছু প্রকাশ করার পিছনে ব্যথা হয়:

if (!name) {
  name = async1();
}
async2(name);

আপনি মাধ্যমে যেতে শেষ হবে async1; nameঅনির্ধারিত কিনা বা না চেক করুন এবং সেই অনুযায়ী কলব্যাক কল।

async1(name, callback) {
  if (name)
    callback(name)
  else {
    doSomething(callback)
  }
}

async1(name, async2)

ছোট ছোট উদাহরণগুলিতে এটি ঠিক আছে তবে এটির ক্ষেত্রে অনেকগুলি সমস্যা রয়েছে এবং ত্রুটিযুক্ত হ্যান্ডলিং জড়িত থাকার সময় এটি বিরক্তিকর হয়ে পড়ে।

Fibers সমস্যা সমাধানে সাহায্য করে।

var Fiber = require('fibers')

function async1(container) {
  var current = Fiber.current
  var result
  doSomething(function(name) {
    result = name
    fiber.run()
  })
  Fiber.yield()
  return result
}

Fiber(function() {
  var name
  if (!name) {
    name = async1()
  }
  async2(name)
  // Make any number of async calls from here
}

আপনি here প্রকল্প চেকআউট করতে পারেন ।


অবশ্যই সমান্তরাল অনুরোধ, প্রতিশ্রুতি মত অনেক পন্থা আছে, কিন্তু আমার অভিজ্ঞতা থেকে আমি মনে করি আপনি কলব্যাক পদ্ধতি ব্যবহার করা উচিত। এটা জাভাস্ক্রিপ্ট এর অ্যাসিঙ্ক্রোনাস আচরণ প্রাকৃতিক। সুতরাং, আপনার কোড স্নিপেটটি একটু ভিন্ন লিখতে পারে:

function foo() {
    var result;

    $.ajax({
        url: '...',
        success: function(response) {
            myCallback(response);
        }
    });

    return result;
}

function myCallback(response) {
    // Does something.
}

আপনার কাছে কোড নিক্ষেপ করার পরিবর্তে, ২ টি ধারণা রয়েছে যা JS কীভাবে কলব্যাকগুলি এবং অ্যাসাইন্রোনসিটিটি পরিচালনা করে তা বোঝার চাবিকাঠি। (এমনকি একটি শব্দ আছে?)

ইভেন্ট লুপ এবং Concurrency মডেল

আপনি সচেতন হতে হবে তিনটি জিনিস আছে; সারি; ইভেন্ট লুপ এবং স্ট্যাক

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

while (queue.waitForMessage()) {
   queue.processNextMessage();
}

এটি কিছু চালানোর জন্য একটি বার্তা পায় একবার এটি কিউ যোগ করে। সারি এমন জিনিসগুলির তালিকা যা চালানোর জন্য অপেক্ষা করছে (যেমন আপনার AJAX অনুরোধ)। এটা কল্পনা করুন:

 1. call foo.com/api/bar using foobarFunc
 2. Go perform an infinite loop
 ... and so on

এই বার্তাগুলির মধ্যে যেকোনো একটি চালানোর সময় এটি ক্যুইউ থেকে বার্তা পপ করে এবং একটি স্ট্যাক তৈরি করে, বার্তাটিতে নির্দেশটি সম্পাদন করতে যাকে অবশ্যই JS চালানোর প্রয়োজন হয়। সুতরাং আমাদের উদাহরণে এটি কল বলা হচ্ছেfoobarFunc

function foobarFunc (var) {
  console.log(anotherFunction(var));
}

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

এখানে মূল জিনিস মৃত্যুদণ্ড আদেশ। এটাই

যখন কিছু চলতে যাচ্ছে

যখন আপনি একটি বহিরাগত পার্টিতে AJAX ব্যবহার করে একটি কল করুন বা কোন অ্যাসিঙ্ক্রোনাস কোড (উদাহরণস্বরূপ একটি সেট টাইমআউট) চালান, জাভাস্ক্রিপ্ট এটি এগিয়ে যাওয়ার আগে একটি প্রতিক্রিয়া উপর নির্ভর করে।

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

সেই কারণে অ্যাসিঙ্ক্রোনাস কার্যকারিতা দিয়ে আমরা কলব্যাক্স নামক জিনিসগুলি ব্যবহার করি । এটা বেশ আক্ষরিক একটি then() মত kinda । যেহেতু আমি কিছু সময়ে কিছু ফেরত দেওয়ার প্রতিশ্রুতি দিয়েছি jQuery নির্দিষ্ট কলব্যাকগুলি ব্যবহার করে deffered.done deffered.failএবং deffered.always(অন্যদের মধ্যে) ব্যবহার করে। আপনি here তাদের সব দেখতে পারেনhere

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

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

function foo(bla) {
  console.log(bla)
}

তাই বেশিরভাগ সময় (কিন্তু সর্বদা নয়) আপনি পাস করবেন fooনাfoo()

আশা করি যে কিছু ধারনা করা হবে। যখন আপনি বিভ্রান্তিকর বলে মনে করেন এমন জিনিসগুলির মুখোমুখি হন - আমি অত্যন্ত কমপক্ষে ডকুমেন্টেশনটি পড়ার সুপারিশ করি এটি কমপক্ষে বুঝতে পারে। এটি আপনাকে অনেক ভাল বিকাশকারী বানিয়ে দেবে।


আমরা নিজেদেরকে এমন একটি মহাবিশ্বের মধ্যে খুঁজে পাই যা একটি মাত্রাস্ত্রের সাথে অগ্রগতি হিসাবে আমরা "সময়" বলি। আমরা আসলে কোন সময় বুঝতে পারছি না, কিন্তু আমরা বিমূর্তীকরণ এবং শব্দভান্ডার তৈরি করেছি যা আমাদেরকে যুক্তিযুক্ত করে এবং "অতীত", "বর্তমান", "ভবিষ্যৎ", "আগে", "পরে" এর বিষয়ে কথা বলে।

আমরা তৈরি কম্পিউটার সিস্টেম - আরো এবং আরো - একটি গুরুত্বপূর্ণ মাত্রা হিসাবে সময় আছে। কিছু জিনিস ভবিষ্যতে ঘটতে সেট আপ করা হয়। তারপর অন্যান্য জিনিস অবশেষে ঘটতে পরে অন্যান্য জিনিস ঘটতে হবে। এটি "আসিয়ানচারনিটিটি" নামক মৌলিক ধারণা। আমাদের ক্রমবর্ধমান নেটওয়ার্কযুক্ত বিশ্বের মধ্যে, অ্যাসাইনোকনিসিটিয়ের সবচেয়ে সাধারণ ক্ষেত্রে কিছু দূরবর্তী সিস্টেমের জন্য অনুরোধের জন্য প্রতিক্রিয়া জানাচ্ছে।

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

var milk = order_milk();
put_in_coffee(milk);

কারণ জেএসের কোন উপায় নেই যে এটি কার্যকর হওয়ার আগে এটি শেষ করার জন্য অপেক্ষাorder_milk করতে হবে put_in_coffee। অন্য কথায়, তা জানে না যে order_milkহয় অ্যাসিঙ্ক্রোনাস এমন কিছু বিষয় যা কিছু ভবিষ্যতে সময় পর্যন্ত দুধ ফলে যাচ্ছে না --is। জেএস, এবং অন্যান্য ঘোষণামূলক ভাষা, অপেক্ষা ছাড়া অন্য একটি বিবৃতি কার্যকর।

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

order_milk(put_in_coffee);

order_milkকিক বন্ধ, দুধ অর্ডার, তারপর, কখন এবং যখন এটি আসে, এটি invokes put_in_coffee

এই কলব্যাক পদ্ধতির সমস্যাটি হল যে এটি একটি ফাংশনের স্বাভাবিক সেম্যান্টিক্সকে তার ফলাফল সম্পর্কিত রিপোর্টিং দূষিত করে return; পরিবর্তে, ফাংশন একটি পরামিতি হিসাবে দেওয়া একটি কলব্যাক কল করে তাদের ফলাফল রিপোর্ট nost আবশ্যক। এছাড়াও, ঘটনাগুলির দীর্ঘ ক্রমগুলির সাথে আচরণ করার সময় এই পদ্ধতিটি দ্রুত অচল হয়ে উঠতে পারে। উদাহরণস্বরূপ, ধরুন, আমি কফিতে দুধ ঢুকানোর জন্য অপেক্ষা করতে চাই, এবং তারপরে কেবল তৃতীয় ধাপে কাজ করি, যেমন কফি পান। আমি এই মত কিছু লিখতে প্রয়োজন শেষ:

order_milk(function(milk) { put_in_coffee(milk, drink_coffee); }

যেখানে put_in_coffeeদুধ ঢুকানোর জন্য আমি উভয় দুধে যাচ্ছি , এবং drink_coffeeদুধের মধ্যে একবার প্রয়োগ করার পরেও এটি কার্যকর করার ( ) কাজ করা। এই কোডটি লিখতে, পড়তে এবং ডিবাগ করা কঠিন হয়ে পড়ে।

এই ক্ষেত্রে, আমরা এই প্রশ্ন কোডটি পুনরায় লিখতে পারি:

var answer;
$.ajax('/foo.json') . done(function(response) {
  callback(response.data);
});

function callback(data) {
  console.log(data);
}

প্রতিশ্রুতি লিখুন

এই "প্রতিশ্রুতি", যা মান একটি বিশেষ ধরনের যা প্রতিনিধিত্ব করে এর ধারণা জন্য প্রেরণা ছিল ভবিষ্যৎ বা অ্যাসিঙ্ক্রোনাস কিছু বাছাই ফলাফল। এটি এমন কিছু প্রতিনিধিত্ব করতে পারে যা ইতিমধ্যে ঘটেছে, অথবা এটি ভবিষ্যতে ঘটতে যাচ্ছে, নাকি এটি কখনোই ঘটতে পারে না। প্রতিশ্রুতিগুলির একটি একক পদ্ধতি আছে, যার নাম thenআপনি প্রতিশ্রুতিটি কার্যকর করার প্রতিশ্রুতি দিয়েছেন যখন প্রতিশ্রুতি উপস্থাপিত হয়েছে।

আমাদের দুধ এবং কফি ক্ষেত্রে, আমরা order_milkদুধ আসার জন্য একটি প্রতিশ্রুতি ফিরিয়ে আনার জন্য ডিজাইন করি , তারপরে নিম্নোক্ত পদক্ষেপ put_in_coffeeহিসাবে নির্দিষ্ট করুন then:

order_milk() . then(put_in_coffee)

এর একটি সুবিধা হলো আমরা ভবিষ্যতের ঘটনার ক্রমগুলি তৈরি করতে এই একসাথে স্ট্রিং করতে পারি ("ক্রেনিং"):

order_milk() . then(put_in_coffee) . then(drink_coffee)

আসুন আপনার বিশেষ সমস্যা প্রতিশ্রুতি প্রয়োগ করুন। আমরা একটি ফাংশন ভিতরে আমাদের অনুরোধ যুক্তি মোড়ানো হবে, যা একটি প্রতিশ্রুতি ফিরে:

function get_data() {
  return $.ajax('/foo.json');
}

প্রকৃতপক্ষে, আমরা যা করেছি তা returnকলটিতে যোগ করা হয়েছে $.ajax। এই কাজ করে কারণ jQuery $.ajaxইতিমধ্যে একটি ধরনের প্রতিশ্রুতি মত জিনিস ফেরত। (অনুশীলনে, বিস্তারিত জানার পরে, আমরা এই কলটি মোড়ানো পছন্দ করি যাতে একটি সত্য প্রতিশ্রুতি ফিরিয়ে আনা যায় অথবা এর জন্য কিছু বিকল্প ব্যবহার করা $.ajaxহয়।) এখন, যদি আমরা ফাইলটি লোড করতে এবং এটি শেষ করতে এবং তারপরে অপেক্ষা করতে চাই কিছু না, আমরা কেবল বলতে পারেন

get_data() . then(do_something)

এই ক্ষেত্রে,

get_data() . 
  then(function(data) { console.log(data); });

প্রতিশ্রুতি ব্যবহার করার সময়, আমরা অনেকগুলি ফাংশন পাস করতে শেষ করি then, তাই এটি প্রায়শই কম কম্প্যাক্ট ES6- শৈলী তীর ফাংশনগুলি ব্যবহার করতে সহায়ক হয়:

get_data() . 
  then(data => console.log(data));

asyncশব্দ

কিন্তু যদি কোড সমেত সমান্তরাল এবং অ্যাসিঙ্ক্রোনাস হয় তবে একেবারে ভিন্ন ভাবে কোড লেখার বিষয়ে অস্পষ্টভাবে অসন্তুষ্ট কিছু আছে। সমান্তরাল জন্য, আমরা লিখুন

a();
b();

কিন্তু যদি aঅ্যাসিনক্রোনাস হয়, প্রতিশ্রুতি সঙ্গে আমরা লিখতে হবে

a() . then(b);

উপরে, আমরা বলেছি "জেএসের কোন উপায় নেই যে এটি দ্বিতীয় কলটি কার্যকর করার আগে এটি শেষ হওয়ার জন্য অপেক্ষা করতে হবে "। এটা কি চমৎকার হবে না যদি জেএস বলার কিছু উপায় ছিল ? এটি দেখা যাচ্ছে যে - awaitকীওয়ার্ড, একটি বিশেষ ধরণের ফাংশনের ভিতরে ব্যবহৃত হয় যা "async" ফাংশন নামে পরিচিত। এই বৈশিষ্ট্যটি ES এর আসন্ন সংস্করণের অংশ, কিন্তু ইতিমধ্যেই বাথেলের মতো সঠিক ট্রান্সলেলারগুলিতে উপলব্ধ রয়েছে। এই সহজভাবে লিখতে পারবেন

async function morning_routine() {
  var milk   = await order_milk();
  var coffee = await put_in_coffee(milk);
  await drink(coffee);
}

আপনার ক্ষেত্রে, আপনি কিছু লিখতে সক্ষম হবে

async function foo() {
  data = await get_data();
  console.log(data);
}

আমি একটি ভয়ঙ্কর খুঁজছেন, হাত আঁকা কমিক সঙ্গে উত্তর দিতে হবে। দ্বিতীয় ছবিটি কারণ কেন আছে resultহয় undefinedআপনার কোড উদাহরণে।


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

// WRONG
var results = [];
theArray.forEach(function(entry) {
    doSomethingAsync(entry, function(result) {
        results.push(result);
    });
});
console.log(results); // E.g., using them, returning them, etc.

উদাহরণ:

// WRONG
var theArray = [1, 2, 3];
var results = [];
theArray.forEach(function(entry) {
    doSomethingAsync(entry, function(result) {
        results.push(result);
    });
});
console.log("Results:", results); // E.g., using them, returning them, etc.

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

যে কাজটি কাজ করে না সেটি হলো যে doSomethingAsyncআপনি যে ফলাফলগুলি ব্যবহার করার চেষ্টা করছেন তা থেকে কলব্যাকগুলি এখনও পর্যন্ত চলবে না।

সুতরাং, যদি আপনার একটি অ্যারের (অথবা কোনও ধরণের তালিকা) থাকে এবং প্রতিটি এন্ট্রির জন্য অ্যাসিনসি ক্রিয়াকলাপগুলি করতে চান তবে আপনার দুটি বিকল্প রয়েছে: সমান্তরাল (ওভারল্যাপিং) ক্রিয়াকলাপগুলি বা সিরিজের (ক্রম অনুসারে অন্যের মধ্যে) ক্রিয়াকলাপ করুন।

সমান্তরাল

আপনি তাদের সবগুলি শুরু করতে পারেন এবং আপনি কতগুলি কলব্যাক আশা করছেন তার ট্র্যাক রাখুন এবং তারপরে আপনি যখন অনেক কলব্যাক পেয়েছেন তখন ফলাফলগুলি ব্যবহার করুন:

var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
    doSomethingAsync(entry, function(result) {
        results[index] = result;
        if (--expecting === 0) {
            // Done!
            console.log("Results:", results); // E.g., using the results
        }
    });
});

উদাহরণ:

var theArray = [1, 2, 3];
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
    doSomethingAsync(entry, function(result) {
        results[index] = result;
        if (--expecting === 0) {
            // Done!
            console.log("Results:", results); // E.g., using the results
        }
    });
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

(আমরা দূরে expectingএবং শুধুমাত্র ব্যবহার করতে পারে results.length === theArray.length, কিন্তু যে theArrayকল অসামান্য যখন পরিবর্তিত হয় যে আমাদের খোলা পাতা ...)

লক্ষ্য করুন কিভাবে আমরা ব্যবহার indexথেকে forEachফলাফল সংরক্ষণ করতে resultsএন্ট্রি এটা সম্পর্কিত হিসাবে একই অবস্থানে, এমনকি যদি ফলাফল আদেশের বাইরে পৌঁছা (যেহেতু ASYNC কল অবশ্যই ক্রম অনুসারে শেষ না করেন তারা শুরু হয়েছে, যা)।

কিন্তু যদি আপনি একটি ফাংশন থেকে যারা ফলাফল ফিরে প্রয়োজন ? অন্যান্য উত্তর হিসাবে নির্দিষ্ট করা হয়েছে, আপনি করতে পারেন না; আপনাকে আপনার ফাংশন গ্রহণ করতে হবে এবং একটি কলব্যাক কল করতে হবে (বা একটি then() ফেরত then() )। এখানে একটি কলব্যাক সংস্করণ:

function doSomethingWith(theArray, callback) {
    var results = [];
    var expecting = theArray.length;
    theArray.forEach(function(entry, index) {
        doSomethingAsync(entry, function(result) {
            results[index] = result;
            if (--expecting === 0) {
                // Done!
                callback(results);
            }
        });
    });
}
doSomethingWith(theArray, function(results) {
    console.log("Results:", results);
});

উদাহরণ:

function doSomethingWith(theArray, callback) {
    var results = [];
    var expecting = theArray.length;
    theArray.forEach(function(entry, index) {
        doSomethingAsync(entry, function(result) {
            results[index] = result;
            if (--expecting === 0) {
                // Done!
                callback(results);
            }
        });
    });
}
doSomethingWith([1, 2, 3], function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

অথবা এখানে Promiseপরিবর্তিত একটি সংস্করণ :

function doSomethingWith(theArray) {
    return new Promise(function(resolve) {
        var results = [];
        var expecting = theArray.length;
        theArray.forEach(function(entry, index) {
            doSomethingAsync(entry, function(result) {
                results[index] = result;
                if (--expecting === 0) {
                    // Done!
                    resolve(results);
                }
            });
        });
    });
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

অবশ্যই, যদি doSomethingAsyncআমাদের ত্রুটিগুলি পাস করে, আমরা rejectযখন একটি ত্রুটি পেয়েছিলাম তখন প্রতিশ্রুতি প্রত্যাখ্যান করার জন্য ব্যবহার করব ।)

উদাহরণ:

function doSomethingWith(theArray) {
    return new Promise(function(resolve) {
        var results = [];
        var expecting = theArray.length;
        theArray.forEach(function(entry, index) {
            doSomethingAsync(entry, function(result) {
                results[index] = result;
                if (--expecting === 0) {
                    // Done!
                    resolve(results);
                }
            });
        });
    });
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

(অথবা বিকল্পভাবে, আপনি doSomethingAsyncএকটি প্রতিশ্রুতি যে একটি প্রতিশ্রুতি ফেরত দিতে পারে , এবং তারপর নিচের কাজ করতে পারে ...)

যদি doSomethingAsyncআপনি একটি then() দেয় , আপনি ব্যবহার করতে পারেন Promise.all:

function doSomethingWith(theArray) {
    return Promise.all(theArray.map(function(entry) {
        return doSomethingAsync(entry, function(result) {
            results.push(result);
        });
    }));
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

উদাহরণ:

function doSomethingWith(theArray) {
    return Promise.all(theArray.map(function(entry) {
        return doSomethingAsync(entry, function(result) {
            results.push(result);
        });
    }));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

উল্লেখ্য যে, Promise.allআপনি যখন প্রতিশ্রুতিবদ্ধ হয়েছেন তখন আপনি যে সকল প্রতিশ্রুতিগুলি দিয়েছেন তার ফলাফলগুলির অ্যারের সাথে তার প্রতিশ্রুতিটি সমাধান করে বা প্রতিশ্রুতিটির প্রথমটি যখন আপনি প্রত্যাখ্যান করেন তখন তার প্রতিশ্রুতি প্রত্যাখ্যান করে।

ক্রম

ধরুন অপারেশন সমান্তরাল হতে চান না? আপনি যদি একে অপরের পর একটিকে চালাতে চান তবে আপনাকে পরবর্তী শুরু করার আগে প্রতিটি অপারেশনটি সম্পূর্ণ করতে হবে। এখানে এমন একটি ফাংশনের একটি উদাহরণ যা এটি করে এবং ফলাফল সহ একটি কলব্যাক কল করে:

function doSomethingWith(theArray, callback) {
    var results = [];
    doOne(0);
    function doOne(index) {
        if (index < theArray.length) {
            doSomethingAsync(theArray[index], function(result) {
                results.push(result);
                doOne(index + 1);
            });
        } else {
            // Done!
            callback(results);
        }
    }
}
doSomethingWith(theArray, function(results) {
    console.log("Results:", results);
});

(যেহেতু আমরা সিরিয়ায় কাজ করছি, আমরা তখনই ব্যবহার করতে পারি results.push(result)যেহেতু আমরা জানি যে আমরা ফলাফলের ফলাফল খুঁজে পাব না। উপরের দিকে আমরা ব্যবহার করতে পারতাম results[index] = result;, কিন্তু নিম্নলিখিত কয়েকটি উদাহরণের মধ্যে আমাদের সূচী নেই ব্যবহার করা.)

উদাহরণ:

function doSomethingWith(theArray, callback) {
    var results = [];
    doOne(0);
    function doOne(index) {
        if (index < theArray.length) {
            doSomethingAsync(theArray[index], function(result) {
                results.push(result);
                doOne(index + 1);
            });
        } else {
            // Done!
            callback(results);
        }
    }
}
doSomethingWith([1, 2, 3], function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

(অথবা, আবার, একটি wrapper নির্মাণ doSomethingAsyncযে জন্য আপনি একটি প্রতিশ্রুতি দেয় এবং নিচের কাজ ...)

যদি doSomethingAsyncআপনি একটি প্রতিশ্রুতি দেয়, যদি আপনি (যেমন একটি transpiler সঙ্গে সম্ভবত ES2017 + + সিনট্যাক্স ব্যবহার করতে পারেন হট্টগোল ), আপনি একটি ব্যবহার করতে পারেন async/await সঙ্গে for-ofএবং await:

async function doSomethingWith(theArray) {
    const results = [];
    for (const entry of theArray) {
        results.push(await doSomethingAsync(entry));
    }
    return results;
}
doSomethingWith(theArray).then(results => {
    console.log("Results:", results);
});

উদাহরণ:

async function doSomethingWith(theArray) {
    const results = [];
    for (const entry of theArray) {
        results.push(await doSomethingAsync(entry));
    }
    return results;
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

আপনি যদি ES2017+ সিনট্যাক্স (এখনও পর্যন্ত) ব্যবহার করতে না পারেন তবে আপনি "প্রতিশ্রুতি হ্রাস" প্যাটার্নের উপর একটি বৈচিত্র ব্যবহার করতে পারেন (এটি স্বাভাবিক প্রতিশ্রুতি কমিয়ে তুলনায় আরও জটিল কারণ আমরা ফলাফলটি এক থেকে পরবর্তীতে অতিক্রম করছি না, বরং এর পরিবর্তে একটি অ্যারে তাদের ফলাফল একত্রিত করা):

function doSomethingWith(theArray) {
    return theArray.reduce(function(p, entry) {
        return p.then(function(results) {
            return doSomethingAsync(entry).then(function(result) {
                results.push(result);
                return results;
            });
        });
    }, Promise.resolve([]));
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

উদাহরণ:

function doSomethingWith(theArray) {
    return theArray.reduce(function(p, entry) {
        return p.then(function(results) {
            return doSomethingAsync(entry).then(function(result) {
                results.push(result);
                return results;
            });
        });
    }, Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

... ES2015 + তীর ফাংশনগুলির সাথে কম কষ্টকর :

function doSomethingWith(theArray) {
    return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
        results.push(result);
        return results;
    })), Promise.resolve([]));
}
doSomethingWith(theArray).then(results => {
    console.log("Results:", results);
});

উদাহরণ:

function doSomethingWith(theArray) {
    return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
        results.push(result);
        return results;
    })), Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}


এটি এমন একটি জায়গা যা দুটি নতুন ডেটাবেসিংয়ের জন্য দুটি নতুন জাভাস্ক্রিপ্ট ফ্রেমওয়ার্ক আপনার জন্য ব্যাপকভাবে কাজ করবে।

সুতরাং যদি আপনি Angular, React বা অন্য ফ্রেমওয়ার্কগুলি ব্যবহার করেন যা দুটি উপায়ে ডেটা বাইন্ডিং করে থাকে তবে এই সমস্যাটি কেবল আপনার জন্য ঠিক করা হয়েছে, তাই সহজ ভাষায়, আপনার ফলাফলটি undefinedপ্রথম পর্যায়ে রয়েছে, তাই আপনি result = undefinedতথ্যটি পাওয়ার আগে আপনি পেয়েছেন , যত তাড়াতাড়ি আপনি ফলাফল পাবেন, এটি আপডেট হবে এবং আপনার অজ্যাক্স কলটির প্রতিক্রিয়া যা নতুন মান নির্ধারণ করা হবে ...

কিন্তু আপনি কীভাবে এটিকে বিশুদ্ধ জাভাস্ক্রিপ্ট বা jQuery এ করতে পারেন যেমন আপনি এই প্রশ্নে জিজ্ঞাসা করেছেন?

আপনি একটি কলব্যাক , প্রতিশ্রুতি এবং সম্প্রতি আপনার জন্য এটি পরিচালনা করার জন্য পর্যবেক্ষণযোগ্য ব্যবহার করতে পারেন , উদাহরণস্বরূপ প্রতিশ্রুতিগুলিতে আমাদের সাফল্য () বা তারপরে কিছু ফাংশন রয়েছে যা আপনার ডেটা যখন আপনার জন্য প্রস্তুত হয় তখন একই সাথে কলব্যাক বা সাবস্ক্রাইব ফাংশনের সাথে উপর পর্যবেক্ষণযোগ্য

উদাহরণস্বরূপ, আপনার ক্ষেত্রে যা আপনি jQuery ব্যবহার করছেন , আপনি এটির মতো কিছু করতে পারেন:

$(document).ready(function(){
    function foo() {
        $.ajax({url: "api/data", success: function(data){
            fooDone(data); //after we have data, we pass it to fooDone
        }});
    };

    function fooDone(data) {
        console.log(data); //fooDone has the data and console.log it
    };

    foo(); //call happens here
});

প্রতিশ্রুতি এবং পর্যবেক্ষক সম্পর্কে আরো তথ্যের জন্য এই অ্যাসাইন স্টাফ করার নতুন উপায় যা।


সংক্ষিপ্ত উত্তর হল, আপনি এই মত একটি callback বাস্তবায়ন করতে হবে:

function callback(response) {
    // Here you can do what ever you want with the response object.
    console.log(response);
}

$.ajax({
    url: "...",
    success: callback
});

সর্বাধিক সমাধানটি একটি জাভাস্ক্রিপ্ট ফাংশন তৈরি করে এবং এটি অজ্যাক্স successকলব্যাকের জন্য কল করে ।

function callServerAsync(){
    $.ajax({
        url: '...',
        success: function(response) {

            successCallback(response);
        }
    });
}

function successCallback(responseObj){
    // Do something like read the response and show data
    alert(JSON.stringify(responseObj)); // Only applicable to JSON response
}

function foo(callback) {

    $.ajax({
        url: '...',
        success: function(response) {
           return callback(null, response);
        }
    });
}

var result = foo(function(err, result){
          if (!err)
           console.log(result);    
}); 





ecmascript-2017