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