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


5504

আমার একটি ফাংশন রয়েছে 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`.

উত্তর:


5699

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

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

সমস্যাটি

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

এখানে একটি সাদৃশ্য রয়েছে যা আশা করে সিঙ্ক্রোনাস এবং অ্যাসিনক্রোনাস প্রবাহকে আরও স্পষ্ট করে তোলে:

সমলয়

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

আপনি যখন "সাধারণ" কোডযুক্ত কোনও ফাংশন কল করেন তখন একই ঘটনা ঘটে:

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

var item = findItem();

// Do something with item
doSomethingElse();

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

অসমনিয়ত

আপনি একই কারণে আবার আপনার বন্ধুকে কল করুন। তবে এবার আপনি তাকে বলবেন যে আপনি তাড়াহুড়া করছেন এবং তিনি আপনাকে আপনার মোবাইল ফোনে ফিরে কল করুন। আপনি স্তব্ধ হয়ে যান, বাড়ি ছেড়ে যান এবং যা যা করার পরিকল্পনা করেছিলেন তা করুন। আপনার বন্ধু আপনাকে একবার কল করলে আপনি সে আপনাকে যে তথ্য দিয়েছিলেন তা নিয়েই আপনি व्यवहार করছেন।

আপনি যখন অ্যাজাক্স অনুরোধটি করেন ঠিক তখনই এটি ঘটছে।

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

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


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

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

কেন খারাপ জিজ্ঞাসা করবেন?

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

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

নিম্নলিখিতটিতে আমরা তিনটি পৃথক সমাধান দেখব যা সমস্ত একে অপরের শীর্ষে নির্মিত হয়:

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

তিনটিই বর্তমান ব্রাউজারগুলিতে এবং নোড 7+ এ উপলব্ধ।


ES2017 +: সাথে প্রতিশ্রুতি async/await

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

async/awaitপ্রতিশ্রুতি শীর্ষে তোলে: একটি asyncফাংশন সর্বদা একটি প্রতিশ্রুতি ফেরত। awaitএকটি প্রতিশ্রুতি "মোড়ানো" হয় এবং প্রতিশ্রুতিটি প্রত্যাখ্যান করা হলে সেই প্রতিশ্রুতিটি সমাধান করা মানটির ফলস্বরূপ বা ত্রুটি নিক্ষেপ করে।

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

আপনি এমডিএন সম্পর্কে asyncএবং আরও পড়তে পারেন 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;
  }
}

// Start an IIFE to use `await` at the top level
(async function(){
  let books = await getAllBooks();
  console.log(books);
})();

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


ফাংশন কলব্যাক গ্রহণ করতে দিন

একটি কলব্যাক কেবল একটি ফাংশন অন্য ফাংশনে পাস করা হয়। এই অন্যান্য ফাংশনটি যখনই প্রস্তুত হবে তখন ফাংশনটি পাস বলে। একটি অ্যাসিনক্রোনাস প্রক্রিয়া প্রসঙ্গে, যখনই অ্যাসিক্রোনাস প্রক্রিয়াটি করা হবে তখন কলব্যাক কল হবে। সাধারণত, ফলাফলটি কলব্যাকে পৌঁছে দেওয়া হয়।

প্রশ্নের উদাহরণে, আপনি 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আমরা fooযখন কল করি তখন আমরা যে ফাংশনটি পাস করি সেটিকে উল্লেখ করবে এবং আমরা কেবল এটিকে প্রেরণ করব success। অর্থাৎ একবার অ্যাজাক্স অনুরোধ সফল হয়ে গেলে, কলব্যাকের প্রতিক্রিয়া $.ajaxকল করে callbackএবং পাস করবে (যার সাথে উল্লেখ করা যেতে পারে result, যেহেতু আমরা কলব্যাকটি এভাবে সংজ্ঞায়িত করেছি)।

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

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

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


ES2015 +: তখন () এর সাথে প্রতিশ্রুতি

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

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

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

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

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
  });

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

প্রতিশ্রুতি সম্পর্কে আরও তথ্য: এইচটিএমএল 5 শিলা - জাভাস্ক্রিপ্ট প্রতিশ্রুতি

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

বিলম্বিত বস্তু হ'ল jQuery এর প্রতিশ্রুতিগুলির কাস্টম বাস্তবায়ন (প্রতিশ্রুতি এপিআই প্রমিতকরণের আগে)। তারা প্রায় প্রতিশ্রুতির মতো আচরণ করে তবে কিছুটা আলাদা এপিআই প্রকাশ করে।

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

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

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

পার্শ্ব নোট: প্রতিশ্রুতি গেটস

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

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এবং ব্যবহারকারীর লগইন হয়েছে এমনভাবে এগিয়ে যাবে good ভাল না।

তবে ঠিক করা সহজ:

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বস্তু ব্যবহার falseকরেন তবে তৃতীয় যুক্তি হিসাবে পাস করুন .open

jQuery এর

আপনি যদি jQuery ব্যবহার করেন তবে আপনি asyncবিকল্পটি সেট করতে পারেন false। নোট করুন যে jQuery 1.8 থেকে এই বিকল্পটি অবচিত করা হয়েছে । তারপরে আপনি হয় একটি successকলব্যাক ব্যবহার করতে পারেন বা jqXHR অবজেক্টেরresponseText সম্পত্তি অ্যাক্সেস করতে পারেন :

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

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

মাথা উঁচু করে! সিঙ্ক্রোনাস জেএসএনপি অনুরোধ করা সম্ভব নয় । এর প্রকৃতির দ্বারা জেএসএনপি সর্বদা অবিচ্ছিন্ন (এই বিকল্পটি বিবেচনা না করার আরও একটি কারণ)।


74
@ পোমি: আপনি jQuery ব্যবহার করতে চান, আপনি এটি অন্তর্ভুক্ত করতে হবে। দয়া করে দস্তাবেজ.জিকিউটি.টিউটোরিয়ালস: গেটিং_স্টার্টড_উইথ_জিকিউরিটি দেখুন
ফেলিক্স ক্লিং

11
সলিউশন 1-এ, সাব জিকুয়েরিতে, আমি এই লাইনটি বুঝতে পারি না: If you use any other jQuery AJAX method, such as $.get, $.getJSON, etc., you have them to $.ajax.(হ্যাঁ, আমি বুঝতে পারি যে আমার নিক এই ক্ষেত্রে একটি
বাজে

31
@ গিবার্বিশ: এমএমএমএইচ, আমি জানি না কীভাবে এটি আরও পরিষ্কার করা যায়। আপনি কি দেখেন যে কীভাবে fooডাকা হয় এবং এটিতে কোনও ফাংশন প্রেরণ করা হয় ( foo(function(result) {....});)? resultএই ফাংশনের অভ্যন্তরে ব্যবহৃত হয় এবং এটি অ্যাজাক্স অনুরোধের প্রতিক্রিয়া। এই ফাংশনটি উল্লেখ করার জন্য, ফোনের প্রথম প্যারামিটারটি একটি বেনামি ফাংশনের পরিবর্তে কল করা callbackএবং নির্ধারিত হয় success। সুতরাং, $.ajaxডাকব callbackযখন অনুরোধ সফল হয়েছে। আমি আরও কিছুটা ব্যাখ্যা করার চেষ্টা করেছি।
ফেলিক্স ক্লিং

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

14
@ জেসি: আমি মনে করি আপনি উত্তরের সেই অংশটি ভুল বুঝেছেন। আপনি $.getJSONযদি Ajax অনুরোধটি সিঙ্ক্রোনাস হতে চান তবে আপনি ব্যবহার করতে পারবেন না । যাইহোক, আপনার অনুরোধটি সিঙ্ক্রোনাস হওয়ার ঘটনা ঘটানো উচিত নয়, যাতে এটি প্রযোজ্য না। আপনার কলব্যাকগুলি ব্যবহার করা উচিত বা প্রতিক্রিয়াটি পরিচালনা করার প্রতিশ্রুতি দেওয়া উচিত, যেমন এটি উত্তরে আগে ব্যাখ্যা করা হয়েছে।
ফেলিক্স ক্লিং

1071

আপনি যদি আপনার কোডটিতে 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'

ফেলিক্স ক্লিং এজেএক্সের জন্য jQuery ব্যবহার করা লোকদের জন্য একটি উত্তর লেখার জন্য একটি দুর্দান্ত কাজ করেছিলেন, আমি সিদ্ধান্ত নিই না এমন লোকদের জন্য একটি বিকল্প সরবরাহ করব।

( দ্রষ্টব্য, নতুন fetchএপিআই, কৌণিক বা প্রতিশ্রুতি ব্যবহারকারীদের জন্য আমি নীচে আরও একটি উত্তর যুক্ত করেছি )


আপনি যার মুখোমুখি হচ্ছেন

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

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

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

এখানে একটি সাধারণ উপমা দেওয়া হল

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

(বেহালার)

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

এই সমস্যার একটি সম্ভাব্য সমাধান হ'ল পুনরায় সক্রিয়ভাবে কোড করা , যখন আপনার প্রোগ্রামটি গণনা শেষ হয়ে যায় তখন কী করা উচিত telling

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

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

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

ব্যবহার হবে:

getFive(onComplete);

যা স্ক্রিনে "5" সতর্ক করা উচিত। (বেহালার)

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

এটি সমাধান করার জন্য মূলত দুটি উপায় রয়েছে:

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

1. সিঙ্ক্রোনাস এজেএক্স - এটি করবেন না !!

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

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

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

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

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কলব্যাক গ্রহণ করার জন্য তৈরি করা যেতে পারে। সম্পূর্ণ হওয়ার পরে কীভাবে প্রতিক্রিয়া জানানো হয় সে সম্পর্কে আমরা আমাদের কোডটি বলব 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();
}

(বেহালার)

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

যদি আপনার এখনও বুঝতে সমস্যা হয় তবে এজেএক্স এমডিএন-এ শুরু করার গাইডটি পড়ুন


20
"সিঙ্ক্রোনাস অনুরোধগুলি কোডের সম্পাদনকে অবরুদ্ধ করে এবং মেমরি এবং ইভেন্টগুলি ফাঁস করতে পারে" কীভাবে একটি সিঙ্ক্রোনাস অনুরোধ মেমরি ফাঁস করতে পারে?
ম্যাথু জি

10
@ ম্যাথেজ জি এই প্রশ্নটিতে আমি একটি অনুগ্রহ যুক্ত করেছি , আমি কী দেখতে পারি তা দেখতে পাচ্ছি। আমি মধ্য সময়ে উত্তরটি উদ্ধৃত করছি।
বেনজামিন গ্রুইনবাউম

17
কেবলমাত্র রেফারেন্সের জন্য, এক্সএইচআর 2 আমাদের onloadহ্যান্ডলারটি ব্যবহার করতে দেয় , যা কেবল তখনই আগুন ধরে readyStateযায় 4। অবশ্যই, এটি IE8 এ সমর্থিত নয়। (iirc, নিশ্চিতকরণের প্রয়োজন হতে পারে))
ফ্লোরিয়ান মার্জাইন

9
কলব্যাক হিসাবে কোনও বেনাম ফাংশন কীভাবে পাস করবেন তার আপনার ব্যাখ্যা বৈধ তবে বিভ্রান্তিকর। উদাহরণ var বার = foo (); একটি পরিবর্তনশীল সংজ্ঞায়িত করার জন্য জিজ্ঞাসা করছে, যেখানে আপনার প্রস্তাবিত foo (ফান্টিম ();}); বারটি সংজ্ঞায়িত করে না
রবি অ্যাভেরিল

396

এক্সএমএলএইচটিপিআরকুয়েস্ট 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 বিরক্তিকর করুন।

এই অ্যাজাক্স কলটির প্রতিক্রিয়া পাওয়ার জন্য দুটি উপায় রয়েছে (এক্সএমএলএইচটিপিপিউইকুয়েস্ট ভের নামটি ব্যবহার করে তিনটি):

সহজতম:

this.response

অথবা যদি কোনও কারণে আপনি bind()ক্লাসে কলব্যাক করেন:

e.target.response

উদাহরণ:

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

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

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

সহজ কিছু না।

এখন কিছু লোক সম্ভবত বলবেন যে রেডিস্টেটচেঞ্জ বা এমনকি এক্সএমএলএইচটিপিআরকোয়েস্ট ভেরিয়েবলের নাম ব্যবহার করা ভাল। ওইটা ভুল.

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

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

অনড্রেস্টেটচেঞ্জ শুধুমাত্র তখনই কার্যকর যখন আপনি 2 রাজ্যে শিরোনাম পেতে চান।

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


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

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]):

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

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

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

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

বলার পরে ... কেন এটি সহজ উপায় করবেন না?


মন্তব্যে উল্লিখিত হিসাবে ত্রুটি && সিঙ্ক্রোনাসের ব্যবহার সম্পূর্ণভাবে উত্তরটির পয়েন্টটি ভেঙে দেয়। সঠিকভাবে অ্যাজাক্স ব্যবহার করার জন্য একটি দুর্দান্ত ছোট উপায় কোনটি?

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

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' ফর্মডাটা হিসাবে পাস করেন তবে এটি ত্রুটি ছুঁড়ে না।

প্রথম ক্ষেত্রে ত্রুটি ভিতরে displayAjax()অধীনে this.statusTextযেমন Method not Allowed

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

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

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

শুধুমাত্র this.typeত্রুটি সেট করা আছে।

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

সুতরাং: আপনি URL টি যথাযথভাবে অনুলিপি করতে এবং পেস্ট করতে সক্ষম হলে ত্রুটি পরীক্ষার দরকার নেই। ;)

পিএস: প্রথম পরীক্ষা হিসাবে আমি এক্স ('এক্স', ডিসপ্লেআজাক্স) লিখেছি ... এবং এটি সম্পূর্ণরূপে একটি প্রতিক্রিয়া পেয়েছে ... ??? তাই আমি যে ফোল্ডারটি এইচটিএমএল অবস্থিত সেখানে পরীক্ষা করেছি এবং সেখানে 'x.xML' নামে একটি ফাইল ছিল। সুতরাং আপনি যদি নিজের ফাইল এক্সএমএলএইচটিপিপ্রকাশ 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');

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

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

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


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

আপনি যদি ফাংশনটি বাড়িয়ে দিতে চান ...

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

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

তবে আপনি এক্সএমএলএইচটিপিপিউকেট 2 দিয়ে প্রচুর স্টাফ করতে পারেন:

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

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


15
যদিও এই উত্তরটি দুর্দান্ত (এবং আমরা সকলেই এক্সএইচআর 2 পছন্দ করি এবং ফাইলের ডেটা পোস্ট করি এবং মাল্টিপার্ট ডেটা সম্পূর্ণ দুর্দান্ত) - এটি জাভাস্ক্রিপ্ট সহ এক্সএইচআর পোস্ট করার জন্য সিনট্যাকটিক চিনি প্রদর্শন করে - আপনি এটি একটি ব্লগ পোস্টে রাখতে চান (আমি এটি চাই) বা এমনকি একটি লাইব্রেরিতে (নাম সম্পর্কে নিশ্চিত নয় x, ajaxবা ভাল xhrহতে পারে :))। আমি দেখতে পাচ্ছি না এটি কীভাবে একটি এজেএক্স কল থেকে প্রতিক্রিয়া ফিরিয়েছে addresses (কেউ এখনও করতে পারে var res = x("url")এবং বুঝতে পারে না কেন এটি কাজ করে না;))। পার্শ্ব নোটে - আপনি যদি cপদ্ধতি থেকে ফিরে এসেছিলেন তবে এটি দুর্দান্ত হবে যাতে ব্যবহারকারীরা errorইত্যাদি দেখতে পারেন
বেনজামিন গ্রুয়েনবাম

25
2.ajax is meant to be async.. so NO var res=x('url')..এই প্রশ্ন এবং উত্তরের পুরো বিষয়টি
হ'ল

3
ফাংশনগুলিতে কেন একটি 'সি' প্যারামিটার রয়েছে, যদি প্রথম লাইনে আপনি তার মানটি যা মুছে ফেলা হয়? আমি কিছু অনুপস্থিত করছি?
ব্রায়ান এইচ।

2
একাধিকবার "var" লেখা এড়াতে আপনি স্থানধারক হিসাবে প্যারামিটারগুলি ব্যবহার করতে পারেন
cocco

11
@ কোকো তাই আপনি কয়েকটি কী-স্ট্রোকগুলি সংরক্ষণ করার জন্য কোনও উত্তরের বিভ্রান্তিমূলক, অপঠনযোগ্য কোড লিখেছেন ? দয়া করে এটি করবেন না।
পাথর

316

আপনি যদি প্রতিশ্রুতি ব্যবহার করে থাকেন তবে এই উত্তরটি আপনার পক্ষে।

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

আপনার কোড এর লাইন বরাবর কিছু হতে হবে:

function foo() {
    var data;
    // or $.get(...).then, or request(...).then, or query(...).then
    fetch("/echo/json").then(function(response){
        data = response.json();
    });
    return data;
}

var result = foo(); // result is always undefined no matter what.

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


মূল বিষয়

ব্রাউজারে এবং NodeJS / io.js সঙ্গে সার্ভারে জাভাস্ক্রিপ্ট সম্পাতবিন্দু মডেল অ্যাসিঙ্ক্রোনাস এবং প্রতিক্রিয়াশীল

যখনই আপনি এমন কোনও পদ্ধতির কল করেন যা প্রতিশ্রুতি ফেরত দেয়, thenহ্যান্ডলারগুলি সর্বদা অবিচ্ছিন্নভাবে কার্যকর করা হয় - এটি হ্যান্ডলারের মধ্যে নেই এমন নীচের কোডের পরে.then

এর অর্থ আপনি যখন সংজ্ঞায়িত হ্যান্ডলারটি ফিরে আসছেন dataতখন thenএখনও কার্যকর হয়নি। এর পরিবর্তে এর অর্থ হ'ল আপনি যে মানটি ফিরিয়ে দিচ্ছেন তা সময় মতো সঠিক মানকে সেট করা হয়নি।

ইস্যুটির জন্য এখানে একটি সাধারণ উপমা দেওয়া হয়েছে:

    function getFive(){
        var data;
        setTimeout(function(){ // set a timer for one second in the future
           data = 5; // after a second, do this
        }, 1000);
        return data;
    }
    document.body.innerHTML = getFive(); // `undefined` here and not 5

এর মান dataহয় undefinedযেহেতু data = 5অংশ এখনো মৃত্যুদন্ড কার্যকর করেননি। এটি সম্ভবত এক সেকেন্ডে কার্যকর হবে তবে ততক্ষণে এটি প্রত্যাবর্তিত মানের সাথে অপ্রাসঙ্গিক।

যেহেতু অপারেশনটি এখনও ঘটেনি (এজ্যাক্স, সার্ভার কল, আইও, টাইমার) আপনি অনুরোধের আগে আপনার কোডটি জানাতে সুযোগ পেলেন যে মানটি কী তা।

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

প্রতিশ্রুতি উপর দ্রুত পুনরুদ্ধার

একটি প্রতিশ্রুতি সময়ের সাথে মান হয় । প্রতিশ্রুতিগুলির রাষ্ট্র থাকে, তারা কোনও মূল্য ছাড়াই মুলতুবি হিসাবে শুরু করে এবং এতে স্থায়ী হতে পারে:

  • পরিপূর্ণ অর্থ যে গণনাটি সফলভাবে শেষ হয়েছে।
  • প্রত্যাখাত অর্থ যে গণনা ব্যর্থ হয়েছে।

একটি প্রতিশ্রুতি কেবল একবারে রাজ্যগুলিকে পরিবর্তন করতে পারে যার পরে এটি সর্বদা সর্বদা একই অবস্থায় থাকবে। আপনি thenহ্যান্ডলারগুলি তাদের মানটি বের করার এবং ত্রুটিগুলি পরিচালনা করার প্রতিশ্রুতিগুলিতে সংযুক্ত করতে পারেন । thenহ্যান্ডলাররা কলগুলিতে শিকল দেওয়ার অনুমতি দেয় । প্রতিশ্রুতিগুলি এপিআই ব্যবহার করে তৈরি করা হয় যা তাদের ফেরত দেয় । উদাহরণস্বরূপ, আরও আধুনিক AJAX প্রতিস্থাপন fetchবা jQuery এর$.get ফেরত প্রতিশ্রুতি।

আমরা যখন কল .thenএকটি প্রতিশ্রুতি এবং এর প্রত্যাবর্তন তা থেকে কিছু - আমরা জন্য একটি প্রতিশ্রুতি পেতে প্রক্রিয়াজাত মান । আমরা যদি আর একটি প্রতিশ্রুতি ফিরে পাই তবে আমরা আশ্চর্যজনক জিনিস পাব, তবে আসুন আমাদের ঘোড়াগুলি ধরে রাখুন।

প্রতিশ্রুতি সহ

আসুন দেখুন আমরা কীভাবে প্রতিশ্রুতি দিয়ে উপরের বিষয়টি সমাধান করতে পারি see প্রথমে, প্রতিশ্রুতিবদ্ধ রাজ্যগুলি সম্পর্কে আমাদের বিলম্ব কার্যকারিতা তৈরির জন্য প্রতিশ্রুতিবদ্ধ কনস্ট্রাক্টর ব্যবহার করে উপরের রাজ্যগুলি সম্পর্কে আমাদের বোধগম্যতা প্রদর্শন করুন :

function delay(ms){ // takes amount of milliseconds
    // returns a new promise
    return new Promise(function(resolve, reject){
        setTimeout(function(){ // when the time is up
            resolve(); // change the promise to the fulfilled state
        }, ms);
    });
}

এখন, আমরা প্রতিশ্রুতি ব্যবহারের জন্য সেটটাইমআউটকে রূপান্তর করার পরে, আমরা thenএটি গণনা করতে ব্যবহার করতে পারি:

function delay(ms){ // takes amount of milliseconds
  // returns a new promise
  return new Promise(function(resolve, reject){
    setTimeout(function(){ // when the time is up
      resolve(); // change the promise to the fulfilled state
    }, ms);
  });
}

function getFive(){
  // we're RETURNING the promise, remember, a promise is a wrapper over our value
  return delay(100).then(function(){ // when the promise is ready
      return 5; // return the value 5, promises are all about return values
  })
}
// we _have_ to wrap it like this in the call site, we can't access the plain value
getFive().then(function(five){ 
   document.body.innerHTML = five;
});

মূলত, একটি ফিরতি পরিবর্তে মান যা আমরা কারণ সম্পাতবিন্দু মডেল ব্যবহার করতে পারবেন না - আমরা একটি ফিরতি করছি মোড়কের একটি মান যে আমরা করতে মোড়ক খোলা সঙ্গে then। এটি এমন একটি বাক্সের মতো যা আপনি খুলতে পারেন then

এটি প্রয়োগ করা হচ্ছে

এটি আপনার আসল এপিআই কলের জন্য একই, আপনি যা করতে পারেন:

function foo() {
    // RETURN the promise
    return fetch("/echo/json").then(function(response){
        return response.json(); // process it inside the `then`
    });
}

foo().then(function(response){
    // access the value inside the `then`
})

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

ES2015 (ES6)

ES6 এমন জেনারেটরগুলি উপস্থাপন করে যা ফাংশনগুলি মাঝখানে ফিরে আসতে পারে এবং তারপরে তারা যে বিন্দুতে ছিল তা আবার শুরু করতে পারে। এটি সাধারণত ক্রমগুলির জন্য দরকারী, উদাহরণস্বরূপ:

function* foo(){ // notice the star, this is ES6 so new browsers/node/io only
    yield 1;
    yield 2;
    while(true) yield 3;
}

একটি ফাংশন যে একটি ফেরৎ পুনরুক্তিকারীর ক্রম উপর 1,2,3,3,3,3,....যা iterated করা যেতে পারে। যদিও এটি নিজস্বভাবে আকর্ষণীয় এবং প্রচুর সম্ভাবনার জায়গা খোলে সেখানে একটি বিশেষ আকর্ষণীয় ঘটনা রয়েছে।

আমরা যে ক্রমটি তৈরি করছি তা যদি সংখ্যার পরিবর্তে ক্রমের ক্রম হয় - আমরা যখনই কোনও ক্রিয়াকলাপ পাওয়া যায় তখন আমরা ফাংশনটি থামিয়ে দিতে পারি এবং ফাংশনটি পুনরায় শুরু করার আগে এটির জন্য অপেক্ষা করতে পারি। সুতরাং সংখ্যার ক্রম পরিবর্তে আমাদের ভবিষ্যতের ক্রম প্রয়োজন মানগুলির - এটি: প্রতিশ্রুতি।

এই কিছুটা কৌশলযুক্ত কিন্তু খুব শক্তিশালী কৌশলটি আমাদেরকে একটি সুসংগত পদ্ধতিতে অ্যাসিনক্রোনাস কোড লিখতে দেয়। বেশ কয়েকটি "রানার" রয়েছেন যা আপনার জন্য এটি করে, একটি লেখার জন্য কোডের একটি সংক্ষিপ্ত কয়েকটি লাইন তবে এই উত্তরের ক্ষেত্রের বাইরে। আমি ব্যবহার করব করা Bluebird এর Promise.coroutineএখানে, কিন্তু মত অন্যান্য চাদরে হয় coবা Q.async

var foo = coroutine(function*(){
    var data = yield fetch("/echo/json"); // notice the yield
    // code here only executes _after_ the request is done
    return data.json(); // data is defined
});

এই পদ্ধতিটি একটি প্রতিশ্রুতি নিজেই দেয়, যা আমরা অন্যান্য কর্টিনগুলি থেকে গ্রহন করতে পারি। উদাহরণ স্বরূপ:

var main = coroutine(function*(){
   var bar = yield foo(); // wait our earlier coroutine, it returns a promise
   // server call done here, code below executes when done
   var baz = yield fetch("/api/users/"+bar.userid); // depends on foo's result
   console.log(baz); // runs after both requests done
});
main();

ES2016 (ES7)

ES7 এ এটিকে আরও মানিক করা হয়েছে, এখনই বেশ কয়েকটি প্রস্তাব রয়েছে তবে সেগুলির মধ্যে আপনি awaitপ্রতিশ্রুতি দিতে পারেন । উপরের ES6 প্রস্তাবনার asyncএবং awaitকীওয়ার্ডগুলি যুক্ত করে এটি কেবল "সুগার" (ভাল সিনট্যাক্স) । উপরোক্ত উদাহরণ তৈরি করা:

async function foo(){
    var data = await fetch("/echo/json"); // notice the await
    // code here only executes _after_ the request is done
    return data.json(); // data is defined
}

এটি এখনও একই প্রতিশ্রুতি দেয় :)


এটি গ্রহণযোগ্য উত্তর হওয়া উচিত। অ্যাসিঙ্কের জন্য +1 / অপেক্ষা করুন (যদিও আমাদের উচিত নয় return await data.json();?)
লুইস ডোনভান

247

আপনি ভুলভাবে Ajax ব্যবহার করছেন। ধারণাটি এটিকে কোনও কিছু ফেরত দেবে না, বরং এর পরিবর্তে ডেটা কলব্যাক ফাংশন বলে কিছু হস্তান্তর করে যা ডেটা পরিচালনা করে।

এটাই:

function handleData( responseData ) {

    // Do what you want with the data
    console.log(responseData);
}

$.ajax({
    url: "hi.php",
    ...
    success: function ( data, status, XHR ) {
        handleData(data);
    }
});

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


13
এই উত্তরটি সম্পূর্ণ অর্থপূর্ণ ... আপনার সাফল্য পদ্ধতিটি কলব্যাকের মধ্যে কেবল একটি কলব্যাক। আপনি ঠিক থাকতে পারে success: handleDataএবং এটি কাজ করবে।
জ্যাকস ジ ャ ッ ク

5
এবং যদি আপনি "হ্যান্ডেলডেটা" এর বাইরে "প্রতিক্রিয়াডাটা" ফিরিয়ে দিতে চান ... :) ... আপনি কীভাবে এটি করবেন ...? ... কারণ সাধারণ
রিটার্নটি এটি আজাক্সের

@ জ্যাকস এবং @ পেশো হিস্টোভ আপনি এই বিষয়টি মিস করেছেন। হ্যান্ডলার জমা দেওয়ার successপদ্ধতি নয়, এটি এর চারপাশের স্কোপ $.ajax
ট্রাভনিক

@ ট্র্যাভনিক আমি এটা মিস করিনি। আপনি যদি হ্যান্ডেলডেটার সামগ্রীগুলি নিয়ে থাকেন এবং সাফল্যের পদ্ধতিতে রাখেন তবে এটি ঠিক একই রকম আচরণ করবে ...
জ্যাক ジ ャ ッ ク

234

সবচেয়ে সহজ সমাধান হ'ল একটি জাভাস্ক্রিপ্ট ফাংশন তৈরি করা এবং এজ্যাক্স 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);    
}); 

3
আমি জানি না কে এটিকে নেতিবাচক ভোট দিয়েছে। তবে এটি এমন একটি কাজ যা প্রায় পুরোপুরি কার্যকর হয়েছে আমি একটি সম্পূর্ণ অ্যাপ্লিকেশন তৈরি করতে এই পদ্ধতির ব্যবহার করেছি। Jquery.ajax ডেটা ফেরত দেয় না উপরের পদ্ধতির ব্যবহার করা আরও ভাল। যদি এটি ভুল হয় তবে দয়া করে এটি করার আরও ভাল উপায় ব্যাখ্যা করুন এবং পরামর্শ দিন।
হেমন্ত বাওয়েল

11
দুঃখিত, আমি একটি মন্তব্য দিতে ভুলে গেছি (আমি সাধারণত করি!)। আমি এটি ডাউনভোট করেছিলাম। ডাউনভোটগুলি প্রকৃত নির্ভুলতা বা অভাব নির্দেশ করে না, তারা প্রসঙ্গে বা অভাবের মধ্যে দরকারীতা নির্দেশ করে। ফেলিক্স প্রদত্ত আপনার উত্তরটি আমি কার্যকর খুঁজে পাচ্ছি না যা ইতিমধ্যে এটি আরও বিস্তারিতভাবে ব্যাখ্যা করে। পার্শ্ব নোটে, আপনি কেন প্রতিক্রিয়াটি জেএসএন হ'ল?
বেনিয়ামিন গ্রুইনবাউম

5
ঠিক আছে .. @ জেনসন অবজেক্টকে স্ট্রিংয়ে রূপান্তর করতে আমি বেঞ্জামিন স্ট্রিংফাই ব্যবহার করেছি। এবং আপনার বক্তব্য পরিষ্কার করার জন্য ধন্যবাদ। আরও বিস্তৃত উত্তর পোস্ট করার বিষয়টি মাথায় রাখবে।
হেমন্ত বাওলে

এবং যদি আপনি "সাফল্যক্যালব্যাক" এর বাইরে "প্রতিক্রিয়া ওবিজে" ফিরিয়ে দিতে চান ... :) ... আপনি কীভাবে এটি করবেন ...? ... কারণ সাধারণ
রিটার্নটি এটি আজাক্সের

221

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

এখানে চিত্র বর্ণনা লিখুন


32
একটি ছবি এক হাজার শব্দের মূল্যবান , ব্যক্তি এ - তার গাড়ি ঠিক করার জন্য বি এর ব্যক্তির বি-কে জিজ্ঞাসা করুন, পরিবর্তে ব্যক্তি বি - অ্যাজাক্স কল করে এবং গাড়ি ফিক্সিংয়ের বিশদগুলির জন্য সার্ভারের কাছ থেকে প্রতিক্রিয়ার জন্য অপেক্ষা করে, যখন প্রতিক্রিয়া পাওয়া যায়, অ্যাজাক্স সাফল্য ফাংশন ব্যক্তিটিকে কল করে বি ফাংশন করে এবং প্রতিক্রিয়ার সাথে যুক্তি হিসাবে এটি পাস করে, ব্যক্তি এ উত্তরটি গ্রহণ করে।
শাইজুত

10
ধারণাটি চিত্রিত করার জন্য আপনি প্রতিটি চিত্রের সাথে কোডের লাইন যুক্ত করলে দুর্দান্ত হবে।
হাসান বৈগ

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

@ বার্লিপিকার:: ডি ব্রিলিয়ান্ট!
জোহানেস ফারেনক্রুগ

159

Angular1

যারা ব্যবহার করছেন তাদের জন্য AngularJS , এই পরিস্থিতিটি পরিচালনা করতে পারেন Promises

এখানে বলা হয়েছে,

প্রতিশ্রুতি অদৃশ্য অ্যাসিনক্রোনাস ফাংশন ব্যবহার করা যেতে পারে এবং একসাথে একাধিক ফাংশন চেইন করতে অনুমতি দেয়।

আপনি একটি সুন্দর ব্যাখ্যা খুঁজে পেতে পারেন এখানেও

নীচে উল্লিখিত দস্তাবেজের উদাহরণ পাওয়া গেল ।

  promiseB = promiseA.then(
    function onSuccess(result) {
      return result + 1;
    }
    ,function onError(err) {
      //Handle error
    }
  );

 // promiseB will be resolved immediately after promiseA is resolved 
 // and its value will be the result of promiseA incremented by 1.

কৌণিক 2 এবং পরে

ইন Angular2নিম্নলিখিত উদাহরণে তাকান, কিন্তু তার সঙ্গে প্রস্তাবিত ব্যবহারের Observablesসঙ্গে Angular2

 search(term: string) {
     return this.http
  .get(`https://api.spotify.com/v1/search?q=${term}&type=artist`)
  .map((response) => response.json())
  .toPromise();

}

আপনি এটি এইভাবে গ্রাস করতে পারেন,

search() {
    this.searchService.search(this.searchField.value)
      .then((result) => {
    this.result = result.artists.items;
  })
  .catch((error) => console.error(error));
}

দেখুন মূল এখানে পোস্ট। তবে টাইপসক্রিপ্ট স্থানীয় es6 প্রতিশ্রুতিগুলিকে সমর্থন করে না , আপনি যদি এটি ব্যবহার করতে চান তবে আপনার এটির জন্য প্লাগইন লাগতে পারে।

উপরন্তু এখানে প্রতিশ্রুতি হল বৈশিষ্ট এখানে নির্ধারণ করুন।


15
এটি প্রতিশ্রুতি দিলেও কীভাবে এই সমস্যাটি সমাধান করবে তা ব্যাখ্যা করে না।
বেনিয়ামিন গ্রুইনবাউম

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

153

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

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

উদাহরণ:

কাজ না করার কারণটি হ'ল 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
        }
    });
});

উদাহরণ:

(আমরা expectingকেবলমাত্র ব্যবহার করতে পারতাম এবং কেবল ব্যবহার করতে পারতাম results.length === theArray.length, তবে theArrayকলগুলি অসামান্য থাকাকালীন পরিবর্তিত হওয়ার সম্ভাবনাটি আমাদের ছেড়ে দেয় ...)

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

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

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);
});

উদাহরণ:

বা 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পেলে প্রতিশ্রুতিটি প্রত্যাখ্যান করতে ব্যবহার করব))

উদাহরণ:

(বা অন্যথায়, আপনি doSomethingAsyncযে প্রতিশ্রুতি ফেরান তার জন্য একটি মোড়ক তৈরি করতে পারেন , এবং তারপরে নীচেটি করুন ...)

যদি doSomethingAsyncআপনাকে কোনও প্রতিশ্রুতি দেয় তবে আপনি এটি ব্যবহার করতে পারেন Promise.all:

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

আপনি যদি জানেন যে এটি doSomethingAsyncদ্বিতীয় এবং তৃতীয় যুক্তিকে উপেক্ষা করবে, আপনি কেবল এটিকে সরাসরি পাস করতে পারেন map( mapতিনটি আর্গুমেন্ট দিয়ে এর কলব্যাক কল করে তবে বেশিরভাগ মানুষ কেবল বেশিরভাগ সময় প্রথমবার ব্যবহার করে):

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

উদাহরণ:

নোট করুন যে 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)যেহেতু আমরা জানি যে আমরা অর্ডার থেকে ফল পাব না the উপরের দিকে আমরা ব্যবহার করতে পারতাম results[index] = result;, তবে নিম্নলিখিত কয়েকটি উদাহরণে আমাদের সূচক নেই ব্যবহার করা.)

উদাহরণ:

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

যদি doSomethingAsyncআপনি একটি প্রতিশ্রুতি দেয়, যদি আপনি ES2017 + + সিনট্যাক্স (সম্ভবত মত একটি transpiler সাথে ব্যবহার করতে পারেন হট্টগোল ), আপনি একটি ব্যবহার করতে পারেন asyncফাংশন সঙ্গে 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);
});

উদাহরণ:

আপনি যদি 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);
});

উদাহরণ:

... যা 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);
});

উদাহরণ:


1
কোডটির if (--expecting === 0)অংশটি কীভাবে কাজ করে তা আপনি ব্যাখ্যা করতে পারেন ? আপনার সমাধানের কলব্যাক সংস্করণটি আমার জন্য দুর্দান্ত কাজ করছে, আমি ঠিক বুঝতে পারি না কীভাবে, এই বিবৃতি দিয়ে আপনি কীভাবে প্রতিক্রিয়া পূর্ণ করেছেন তা পরীক্ষা করে দেখছেন। এটি আমার পক্ষ থেকে জ্ঞানের অভাব প্রশংসা করুন। বিকল্প উপায় আছে যা চেক লেখা যেতে পারে?
সারা

@ সারাহ: expectingএর মান দিয়ে শুরু হয় array.lengthযা আমরা কতগুলি অনুরোধ করব। আমরা জানি যে সমস্ত অনুরোধ শুরু না হওয়া পর্যন্ত কলব্যাক কল করা হবে না। কলব্যাকে if (--expecting === 0)এটি করুন: ১. হ্রাস expecting(আমরা একটি প্রতিক্রিয়া পেয়েছি, সুতরাং আমরা আরও একটি কম প্রতিক্রিয়া আশা করব) এবং যদি হ্রাসের পরে মান 0 হয় (আমরা আর কোনও প্রতিক্রিয়া আশা করি না), আমরা সম্পন্ন!
টিজে ক্রাউডার

1
@ পেট্রিকরোবার্টস - ধন্যবাদ !! হ্যাঁ, অনুলিপি-অনুলিপি ত্রুটি, সেই দ্বিতীয় যুক্তিটি সেই উদাহরণে সম্পূর্ণ উপেক্ষা করা হয়েছিল (এটি কেবলমাত্র ব্যর্থ হয়নি, কারণ আপনি উল্লেখ করেছেন যে, resultsএটি বিদ্যমান ছিল না)। :-) ঠিক কর.
টিজে ক্রাউডার

111

এই উদাহরণটি দেখুন:

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope,$http) {

    var getJoke = function(){
        return $http.get('http://api.icndb.com/jokes/random').then(function(res){
            return res.data.value;  
        });
    }

    getJoke().then(function(res) {
        console.log(res.joke);
    });
});

যেহেতু আপনি দেখতে পারেন getJokeহয় একটি ফিরতি সমাধান প্রতিশ্রুতি (এটা যখন ফিরে সমাধান করা res.data.value)। সুতরাং আপনি $ http.get অনুরোধটি শেষ না হওয়া পর্যন্ত অপেক্ষা করুন এবং তারপরে কনসোল.লগ (রেস.জোক) কার্যকর করা হবে (একটি সাধারণ অ্যাসিনক্রোনাস প্রবাহ হিসাবে)।

এই plnkr:

http://embed.plnkr.co/XlNR7HpCaIhJxskMJfSg/

ES6 উপায় (async - অপেক্ষা করুন)

(function(){
  async function getJoke(){
    let response = await fetch('http://api.icndb.com/jokes/random');
    let data = await response.json();
    return data.value;
  }

  getJoke().then((joke) => {
    console.log(joke);
  });
})();

107

এটি সেই জায়গাগুলির মধ্যে একটি যা দুটি উপায় ডেটা বাঁধাই বা স্টোর ধারণা যা অনেক নতুন জাভাস্ক্রিপ্ট ফ্রেমওয়ার্কগুলিতে ব্যবহার করা আপনার পক্ষে দুর্দান্ত কাজ করবে ...

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

তবে আপনি খাঁটি জাভাস্ক্রিপ্ট বা jQuery এ এটি কীভাবে করতে পারেন উদাহরণস্বরূপ আপনি এই প্রশ্নে জিজ্ঞাসা করেছেন?

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

উদাহরণস্বরূপ আপনার ক্ষেত্রে যা আপনি 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
});

প্রতিশ্রুতি এবং পর্যবেক্ষণযোগ্য যা এই অ্যাসিঙ্ক স্টাফগুলি করার নতুন উপায় about


এটি বৈশ্বিক সুযোগে ঠিক আছে তবে কিছু মডিউল প্রসঙ্গে আপনি সম্ভবত কলব্যাকের জন্য সঠিক প্রসঙ্গটি নিশ্চিত করতে চান যেমন$.ajax({url: "api/data", success: fooDone.bind(this)});
স্টিভ.সিমস

8
এটি আসলে ভুল হিসাবে প্রতিক্রিয়া একমুখী তথ্য বাঁধাই হয়
ম্যাথু ব্রেন্ট

@ ম্যাথেজব্রেন্ট আপনি ভুল নন, তবে ঠিকও নয়, প্রতিক্রিয়াযুক্ত প্রপাগুলি আপত্তিজনক হয় এবং যদি পরিবর্তিত হয়, তবে তারা অ্যাপ্লিকেশন জুড়ে পরিবর্তিত হয়, তবে এটি এমন কোনও উপায় নয় যা প্রতিক্রিয়া বিকাশকারী এটি ব্যবহার করার পরামর্শ দেয় ...
আলিরিজা

98

এটি জাভাস্ক্রিপ্টের 'রহস্যের' সাথে লড়াই করার সময় আমরা খুব সাধারণ একটি সমস্যা। আমাকে আজ এই রহস্যটিকে অপ্রত্যাশিত করার চেষ্টা করুন।

আসুন একটি সাধারণ জাভাস্ক্রিপ্ট ফাংশন দিয়ে শুরু করুন:

function foo(){
// do something 
 return 'wohoo';
}

let bar = foo(); // bar is 'wohoo' here

এটি একটি সাধারণ সিঙ্ক্রোনাস ফাংশন কল (যেখানে কোডের প্রতিটি লাইন ক্রমান্বয়ে পরেরটির আগে 'এর কাজ দিয়ে শেষ হয়'), এবং ফলাফলটি প্রত্যাশার মতোই।

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

function foo(){
 setTimeout( ()=>{
   return 'wohoo';
  }, 1000 )
}

let bar = foo() // bar is undefined here

সুতরাং আপনি সেখানে যান, এই বিলম্বটি কেবল আমাদের প্রত্যাশিত কার্যকারিতাটি ভেঙে দিয়েছে! তবে ঠিক কী হয়েছিল? ঠিক আছে, আপনি কোডটি দেখুন যদি এটি আসলে বেশ যৌক্তিক। ফাংশনটি foo()কার্যকর হওয়ার পরে কিছুই প্রদান করে না (যেমন undefinedপ্রত্যাশিত মানটি হয় ) তবে এটি একটি টাইমার শুরু করে যা 1s এর পরে 'ওহু' ফেরত ফাংশন সম্পাদন করে। তবে আপনি দেখতে পাচ্ছেন যে বারটির জন্য নির্ধারিত মান হ'ল foo () থেকে তত্ক্ষণাত্ ফিরিয়ে দেওয়া সামগ্রী, যা কিছুই ঠিক নেই undefined

সুতরাং, আমরা কীভাবে এই সমস্যাটি মোকাবেলা করব?

চলুন একটি ফর্মসের জন্য আমাদের ফাংশন জিজ্ঞাসা করুন । প্রতিশ্রুতি তার অর্থ সম্পর্কে সত্যই: এর অর্থ হল যে ফাংশনটি আপনাকে ভবিষ্যতে যে কোনও আউটপুট সরবরাহ করার গ্যারান্টি দেয়। সুতরাং আসুন এটি আমাদের উপরের সামান্য সমস্যার জন্য ক্রিয়াতে দেখুন:

function foo(){
   return new Promise( (resolve, reject) => { // I want foo() to PROMISE me something
    setTimeout ( function(){ 
      // promise is RESOLVED , when execution reaches this line of code
       resolve('wohoo')// After 1 second, RESOLVE the promise with value 'wohoo'
    }, 1000 )
  })
}

let bar ; 
foo().then( res => {
 bar = res;
 console.log(bar) // will print 'wohoo'
});

সুতরাং, সংক্ষিপ্তসারটি হ'ল - এজ্যাক্স ভিত্তিক কল ইত্যাদির মতো অ্যাসিনক্রোনাস ফাংশনগুলি মোকাবেলা করার জন্য, আপনি resolveমানটির প্রতিশ্রুতি (যা আপনি প্রত্যাবর্তন করতে চান) ব্যবহার করতে পারেন। সুতরাং, সংক্ষেপে আপনি অ্যাসিক্রোনাস ফাংশনগুলিতে ফিরে আসার পরিবর্তে মান সমাধান করেন

আপডেট (async / প্রতীক্ষার সাথে প্রতিশ্রুতি)

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

তারপরে / ধরুন সংস্করণ:

function saveUsers(){
     getUsers()
      .then(users => {
         saveSomewhere(users);
      })
      .catch(err => {
          console.error(err);
       })
 }

সংস্করণ / অপেক্ষার সংস্করণ:

  async function saveUsers(){
     try{
        let users = await getUsers()
        saveSomewhere(users);
     }
     catch(err){
        console.error(err);
     }
  }

এটি কি এখনও প্রতিশ্রুতি বা async / প্রতীক্ষার থেকে কোনও মূল্য ফেরত দেওয়ার সেরা উপায় হিসাবে বিবেচিত হয়?
edwardsmarkf

3
@edwardsmarkf ব্যক্তিগতভাবে আমি মনে করি না এর মতো সর্বোত্তম উপায় আছে। আমি তখন / ক্যাচ, অ্যাসিঙ্ক / অপেক্ষার পাশাপাশি জেনারেটরগুলির সাথে আমার কোডের অ্যাসিঙ্ক অংশগুলির জন্য প্রতিশ্রুতি ব্যবহার করি। এটি মূলত ব্যবহারের প্রসঙ্গে নির্ভর করে।
আনিস কে।

96

অ্যাসিঙ্ক্রোনাস ফাংশন থেকে কোনও মান ফেরত দেওয়ার জন্য আরেকটি পদ্ধতি হ'ল এমন একটি বস্তুতে পাস করা যা ফলকে অ্যাসিঙ্ক্রোনাস ফাংশন থেকে সংরক্ষণ করবে।

এখানে এর উদাহরণ রয়েছে:

var async = require("async");

// This wires up result back to the caller
var result = {};
var asyncTasks = [];
asyncTasks.push(function(_callback){
    // some asynchronous operation
    $.ajax({
        url: '...',
        success: function(response) {
            result.response = response;
            _callback();
        }
    });
});

async.parallel(asyncTasks, function(){
    // result is available after performing asynchronous operation
    console.log(result)
    console.log('Done');
});

আমি ব্যবহার করছি resultঅ্যাসিক্রোনাস অপারেশনের সময় আমি মানটি সঞ্চয় অবজেক্টটি । এটি অ্যাসিঙ্ক্রোনাস কাজের পরেও ফলাফলটি উপলব্ধ হতে দেয়।

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


9
এখানে কোনও জিনিস ব্যবহার করার জন্য বিশেষ কিছু নেই। আপনি যদি সরাসরি প্রতিক্রিয়া জানান তবে এটি কাজ করবে result। এটি কাজ করে কারণ আপনি অ্যাসিঙ্ক ফাংশনটি সম্পূর্ণ হওয়ার পরে পরিবর্তনশীলটি পড়ছেন ।
ফেলিক্স ক্লিং

85

যদিও প্রতিশ্রুতি এবং কলব্যাকগুলি অনেক পরিস্থিতিতে ঠিকঠাক কাজ করে, এমন কিছু প্রকাশ করার পিছনে ব্যথা হয়:

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
}

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


1
@ রিচার্ফ - এটি আমার প্রকল্প নয়। আপনি তাদের সমস্যা ট্র্যাকার ব্যবহার করে দেখতে পারেন।
রোহিথপ্রি

1
এটি কি জেনারেটরের কাজগুলির সাথে সমান? বিকাশকারী.মোজিলা.আর.ইন-
ইউএস

1
এটি কি এখনও প্রাসঙ্গিক?
আলুয়ান হাদাদ

আপনি async-awaitনোডের কয়েকটি নতুন সংস্করণ ব্যবহার করছেন তবে আপনি এটি ব্যবহার করতে পারেন । যদি কেউ পুরানো সংস্করণে আটকে থাকে তবে তারা এই পদ্ধতিটি ব্যবহার করতে পারেন।
রোহিথপ্রিপ

83

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

  • অ্যাসিঙ্ক্রোনাস এইচটিটিপি কলগুলি পরিচালনা করুন;
  • প্রতিটি এপিআই কল থেকে প্রতিক্রিয়ার জন্য অপেক্ষা করুন;
  • প্রতিশ্রুতি প্যাটার্ন ব্যবহার করুন ;
  • একাধিক এইচটিটিপি কলগুলিতে যোগ দিতে প্রতিশ্রুতি। সমস্ত প্যাটার্ন ব্যবহার করুন ;

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

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

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

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

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

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

-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" />

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


80

সংক্ষিপ্ত উত্তরটি হ'ল, আপনাকে এই জাতীয় কলব্যাক প্রয়োগ করতে হবে:

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

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

78

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

এটি বেশ সহজ:

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

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

(async function(){

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

})()

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


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

2
@ MichałPerłakowski নোড 8 এর মধ্যে nodejs.org/api/util.html#util_util_promisif_original অন্তর্ভুক্ত যা নোড.জেএসপি এপিআই রিটার্ন প্রতিশ্রুতি তৈরি করতে ব্যবহার করা যেতে পারে। অ-বর্তমান ব্রাউজারগুলিকে সমর্থন করার জন্য আপনার কাছে সময় এবং অর্থ রয়েছে কিনা তা আপনার অবস্থার উপর নির্ভর করে।
মাইকমেকানা

দুঃখের সাথে আইই 11 এখনও 2018 এর একটি বর্তমান ব্রাউজার, এটি সমর্থন করে নাawait/async
জুয়ান মেন্ডেস

আইই 11 কোনও বর্তমান ব্রাউজার নয়। এটি 5 বছর আগে প্রকাশিত হয়েছিল, ক্যানিউজ অনুসারে বিশ্বব্যাপী বাজারের শেয়ারের পরিমাণ 2.5% এবং যদি কেউ আপনার বর্তমান বাজেটকে বর্তমান প্রযুক্তিটিকে উপেক্ষা করতে দ্বিগুণ না করে তবে এটি বেশিরভাগ মানুষের জন্য উপযুক্ত নয়।
মাইকমেকানা

76

জেএস একক থ্রেডযুক্ত।

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

1) ইভেন্ট লুপ

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

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

ইভেন্ট লুপ চিরতরে অর্থাত্‍ এক ধরণের অসীম লুপের জন্য চলে vent আপনার সমস্ত ফাংশন কোনও ইভেন্টে চাপ দেওয়া হয় (উদাহরণস্বরূপ: ক্লিক করুন) এটি একের পর এক সারিবদ্ধভাবে সঞ্চালিত হয় এবং ইভেন্ট লুপে রাখা হয় যা এই ফাংশনটি সম্পাদন করে এবং নিজেকে প্রস্তুত করে ares প্রথমটির মৃত্যুর পরের জন্য পরবর্তীটির জন্য। এর অর্থ ইভেন্ট লুপে সারিতে সঞ্চালিত হওয়ার আগে ফাংশনটি কার্যকর হওয়া অবধি শুরু হয় না।

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

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

সুতরাং এটির সমাধান কলব্যাক বা প্রতিশ্রুতি

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

কলব্যাক

 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");
}

জাভাস্ক্রিপ্ট.ইনফো কলব্যাক


68

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

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)
});

67

আরেকটি সমাধান হ'ল সিক্যুয়ালি এক্সিকিউটার এনসাইঞ্জের মাধ্যমে কোড চালানো ।

অন্তর্নিহিত ফাংশন যদি প্রচার করা হয়

এনসিএনজগুলি সমস্ত প্রতিশ্রুতিগুলি ধারাবাহিকভাবে মূল্যায়ন করবে এবং প্রতিশ্রুতি ফলাফলকে dataসম্পত্তি হিসাবে দেবে:

function synchronousCode() {

    var getURL = function(url) {
        return window.fetch(url).data.text().data;
    };
    
    var url = 'https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js';
    console.log('received bytes:',getURL(url).length);
    
};

nsynjs.run(synchronousCode,{},function(){
    console.log('synchronousCode done');
});
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>

অন্তর্নিহিত ফাংশন প্রচারিত না হলে

পদক্ষেপ 1. কল-ব্যাক সঙ্গে nsynjs- সচেতন মোড়কে ফাংশন মোড়ানো (যদি এটির সংস্করণ দেওয়া থাকে, আপনি এই পদক্ষেপটি এড়িয়ে যেতে পারেন):

var ajaxGet = function (ctx,url) {
    var res = {};
    var ex;
    $.ajax(url)
    .done(function (data) {
        res.data = data;
    })
    .fail(function(e) {
        ex = e;
    })
    .always(function() {
        ctx.resume(ex);
    });
    return res;
};
ajaxGet.nsynjsHasCallback = true;

পদক্ষেপ 2. সিঙ্ক্রোনাস যুক্তি ফাংশনে রাখুন:

function process() {
    console.log('got data:', ajaxGet(nsynjsCtx, "data/file1.json").data);
}

পদক্ষেপ 3. এনসিঞ্জের মাধ্যমে সিঙ্ক্রোনাস পদ্ধতিতে ফাংশন পরিচালনা করুন:

nsynjs.run(process,this,function () {
    console.log("synchronous function finished");
});

Nsynjs ধাপে ধাপে সমস্ত অপারেটর এবং এক্সপ্রেশনকে মূল্যায়ন করবে, যদি কিছু ধীর গতির ফলস্বরূপ ফলাফল প্রস্তুত না হয় তবে ক্ষেত্রে মৃত্যুদন্ড কার্যকর করতে বিরতি দিন।

আরও উদাহরণ এখানে: https://github.com/amaksr/nsynjs/tree/master/ex উদাহরণ


2
এটা মজার. আমি পছন্দ করি যে এটি অন্যান্য সংস্থাগুলিতে যেভাবে এসিংকে কল করবে সেটি কোড করার অনুমতি দেয়। কিন্তু প্রযুক্তিগতভাবে এটি বাস্তব জাভাস্ক্রিপ্ট নয়?
জে মরিস

41

ইসমাস্ক্রিপ্ট-এর 'জেনারেটর' রয়েছে যা আপনাকে সহজেই অ্যাসিনক্রোনাস স্টাইলে প্রোগ্রাম করার অনুমতি দেয়।

function* myGenerator() {
    const callback = yield;
    let [response] = yield $.ajax("https://stackoverflow.com", {complete: callback});
    console.log("response is:", response);

    // examples of other things you can do
    yield setTimeout(callback, 1000);
    console.log("it delayed for 1000ms");
    while (response.statusText === "error") {
        [response] = yield* anotherGenerator();
    }
}

উপরের কোডটি চালানোর জন্য আপনি এটি করুন:

const gen = myGenerator(); // Create generator
gen.next(); // Start it
gen.next((...args) => gen.next([...args])); // Set its callback function

আপনার যদি ES6 সমর্থন করে না এমন ব্রাউজারগুলি লক্ষ্যবস্তু করা দরকার আপনি ECMAScript 5 উত্পন্ন করতে বাবেল বা ক্লোজার-কম্পাইলারের মাধ্যমে কোড চালাতে পারেন।

কলব্যাকটি ...argsএকটি অ্যারেতে আবৃত হয় এবং যখন আপনি সেগুলি পড়েন তখন ডেস্ট্রাকচার করা হয় যাতে প্যাটার্নটি কলব্যাকগুলি মোকাবেলা করতে পারে যাতে একাধিক যুক্তি রয়েছে। উদাহরণস্বরূপ নোড এফএস সহ :

const [err, data] = yield fs.readFile(filePath, "utf-8", callback);

39

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

  1. ব্রাউজার প্রতিশ্রুতি বস্তু
  2. প্রশ্ন - জাভাস্ক্রিপ্টের জন্য একটি প্রতিশ্রুতি পাঠাগার
  3. এ + প্রতিশ্রুতি .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();


38

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

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

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

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

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

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

order_milk(put_in_coffee);

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

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

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

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

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

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

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

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

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

আমাদের দুধ এবং কফির ক্ষেত্রে, আমরা 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);
}

37

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

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

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()এখনও কার্যকর কিছু ফিরিয়ে দেবে না। তবে, অ্যাসিঙ্ক কলের ফলাফল এখন সংরক্ষণ করা হবে result.response


14
এটি যখন কাজ করে, বিশ্বব্যাপী ভেরিয়েবলের দায়িত্ব দেওয়ার চেয়ে এটি আরও ভাল নয়।
ফেলিক্স ক্লিং

36

সাফল্যের callback()ভিতরে একটি ফাংশন ব্যবহার করুন foo()। এইভাবে চেষ্টা করুন। এটি সহজ এবং বোধগম্য।  

var lat = "";
var lon = "";
function callback(data) {
    lat = data.lat;
    lon = data.lon;
}
function getLoc() {
    var url = "http://ip-api.com/json"
    $.getJSON(url, function(data) {
        callback(data);
    });
}

getLoc();

29

প্রশ্নটি ছিল:

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

যা ব্যাখ্যা করা যেতে পারে:

কিভাবে করতে অ্যাসিঙ্ক্রোনাস কোড বর্ণন সমলয় ?

সমাধানটি হ'ল কলব্যাকগুলি এড়ানো, এবং প্রতিশ্রুতি এবং অ্যাসিঙ্ক / অপেক্ষার সংমিশ্রণটি ব্যবহার করা ।

আমি একটি Ajax অনুরোধের জন্য একটি উদাহরণ দিতে চাই।

(যদিও এটি জাভাস্ক্রিপ্টে লেখা যেতে পারে, আমি পাইথনে এটি লিখতে পছন্দ করি এবং ট্রান্সক্রিপ্ট ব্যবহার করে এটি জাভাস্ক্রিপ্টে সংকলন করি It এটি যথেষ্ট পরিষ্কার হবে))

প্রথমে জিকুয়ের ব্যবহার সক্ষম করতে দেয়, এর জন্য $উপলব্ধ হিসাবে S:

__pragma__ ('alias', 'S', '$')

কোনও ফাংশন সংজ্ঞায়িত করুন যা প্রতিশ্রুতি দেয় , এক্ষেত্রে একটি অ্যাজাক্স কল:

def read(url: str):
    deferred = S.Deferred()
    S.ajax({'type': "POST", 'url': url, 'data': { },
        'success': lambda d: deferred.resolve(d),
        'error': lambda e: deferred.reject(e)
    })
    return deferred.promise()

অ্যাসিক্রোনাস কোডটি ব্যবহার করুন যেন এটি সিঙ্ক্রোনাস হয় :

async def readALot():
    try:
        result1 = await read("url_1")
        result2 = await read("url_2")
    except Exception:
        console.warn("Reading a lot failed")

29

প্রতিশ্রুতি ব্যবহার

এই প্রশ্নের সবচেয়ে নিখুঁত উত্তর ব্যবহার করছে Promise

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

ব্যবহার

ajax("GET", "/test", "acrive=1").then(function(result) {
    // Code depending on result
})
.catch(function() {
    // An error occurred
});

কিন্তু অপেক্ষা করো...!

প্রতিশ্রুতি ব্যবহারে সমস্যা আছে!

কেন আমাদের নিজস্ব কাস্টম প্রতিশ্রুতি ব্যবহার করা উচিত?

আমি পুরানো ব্রাউজারগুলিতে একটি ত্রুটি না হওয়া পর্যন্ত আমি এই সমাধানটি কিছুক্ষণ ব্যবহার করছিলাম:

Uncaught ReferenceError: Promise is not defined

সুতরাং আমি ইএস 3 এর নীচে জেএস সংকলকগুলির জন্য নিজের নিজস্ব প্রতিশ্রুতি শ্রেণীর প্রয়োগ করার সিদ্ধান্ত নিয়েছি যদি এটির সংজ্ঞা না দেওয়া হয়। আপনার মূল কোডের আগে এই কোডটি যুক্ত করুন এবং তারপরে নিরাপদে প্রতিশ্রুতিটি ব্যবহার করুন!

if(typeof Promise === "undefined"){
    function _classCallCheck(instance, Constructor) {
        if (!(instance instanceof Constructor)) { 
            throw new TypeError("Cannot call a class as a function"); 
        }
    }
    var Promise = function () {
        function Promise(main) {
            var _this = this;
            _classCallCheck(this, Promise);
            this.value = undefined;
            this.callbacks = [];
            var resolve = function resolve(resolveValue) {
                _this.value = resolveValue;
                _this.triggerCallbacks();
            };
            var reject = function reject(rejectValue) {
                _this.value = rejectValue;
                _this.triggerCallbacks();
            };
            main(resolve, reject);
        }
        Promise.prototype.then = function then(cb) {
            var _this2 = this;
            var next = new Promise(function (resolve) {
                _this2.callbacks.push(function (x) {
                    return resolve(cb(x));
                });
            });
            return next;
        };
        Promise.prototype.catch = function catch_(cb) {
            var _this2 = this;
            var next = new Promise(function (reject) {
                _this2.callbacks.push(function (x) {
                    return reject(cb(x));
                });
            });
            return next;
        };
        Promise.prototype.triggerCallbacks = function triggerCallbacks() {
            var _this3 = this;
            this.callbacks.forEach(function (cb) {
                cb(_this3.value);
            });
        };
        return Promise;
    }();
}

28

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

function foo() {
    var result;

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

    return result;
}

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

5
কলব্যাকস বা জাভাস্ক্রিপ্ট সম্পর্কে সহজাতভাবে অ্যাসিঙ্ক্রোনাস কিছুই নেই।
আলুয়ান হাদাদ

19

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

ইভেন্ট লুপ এবং কনকুরেন্সি মডেল

তিনটি বিষয় সম্পর্কে আপনার সচেতন হওয়া দরকার; সারি; ইভেন্ট লুপ এবং স্ট্যাক

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

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

এটি একবার চালানোর জন্য কোনও বার্তা পেলে এটিকে কাতারে যুক্ত করে। কিউ হ'ল কার্যকর করার জন্য অপেক্ষা করা জিনিসগুলির তালিকা (আপনার এজেএক্স অনুরোধের মতো)। এটি এইভাবে কল্পনা করুন:

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

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

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

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

এখানে মূল বিষয়টি হ'ল মৃত্যুদণ্ড কার্যকর করা। এটাই

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

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

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

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

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

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

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

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

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


18

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)

})

দ্বিতীয় ফাংশন কি পুনরায় ব্যবহারযোগ্য হতে পারে ??
জুম ড্মি

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