অ্যাসিঙ্ক্রোনাস কলব্যাক ফাংশন সেট করার জন্য আমি কীভাবে অপেক্ষা করতে পারি?


95

আমার কাছে কোড রয়েছে যা জাভাস্ক্রিপ্টে এরকম কিছু দেখাচ্ছে:

forloop {
    //async call, returns an array to its callback
}

এই সমস্ত অ্যাসিঙ্ক কলগুলি সম্পন্ন হওয়ার পরে, আমি সমস্ত অ্যারে থেকে মিনিট গণনা করতে চাই।

আমি কীভাবে তাদের সবার জন্য অপেক্ষা করতে পারি?

এখনই আমার একমাত্র ধারণা হ'ল বুলিয়ানগুলির একটি অ্যারে সম্পন্ন করা এবং আইথ কলব্যাক ফাংশনটিতে [i] সত্য করে সেট করা, তারপরে বলুন (সমস্ত কিছুই সম্পন্ন হয় না) {say

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

আগাম ধন্যবাদ.


4
অ্যাসিঙ্কে আপনি কী বোঝাতে চাইছেন কোন অ্যাজাক্স অনুরোধটি সম্পূর্ণ হওয়ার জন্য অপেক্ষা করছেন?
পিটার আরন জেন্টাই

7
নোট, while (not all are done) { }কাজ করবে না। আপনি যখন ব্যস্ত-অপেক্ষায় রয়েছেন, আপনার কলব্যাকগুলির কোনওটি চলতে পারে না।
সিএইচও

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

আপনি এটি চেষ্টা করতে পারেন: github.com/caolan/async অ্যাসিঙ্ক ইউটিলিটি ফাংশনের খুব সুন্দর সেট।
পল গ্রেসন

উত্তর:


192

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

ম্যানুয়াল কাউন্টার

var ajaxCallsRemaining = 10;
var returnedData = [];

for (var i = 0; i < 10; i++) {
    doAjax(whatever, function(response) {
        // success handler from the ajax call

        // save response
        returnedData.push(response);

        // see if we're done with the last ajax call
        --ajaxCallsRemaining;
        if (ajaxCallsRemaining <= 0) {
            // all data is here now
            // look through the returnedData and do whatever processing 
            // you want on it right here
        }
    });
}

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


jQuery প্রতিশ্রুতি

২০১৪ সালে আমার উত্তরে যোগ করা These আজকাল, প্রতিশ্রুতিগুলি প্রায়শই এই ধরণের সমস্যা সমাধানের জন্য ব্যবহৃত হয় যেহেতু jQuery এর $.ajax()ইতিমধ্যে একটি প্রতিশ্রুতি প্রত্যাবর্তন করেছে এবং $.when()যখন আপনাকে প্রতিশ্রুতিগুলির একটি গোষ্ঠী সমস্ত সমাধান হয়ে যায় এবং আপনাকে ফলাফলগুলি সংগ্রহ করবে:

var promises = [];
for (var i = 0; i < 10; i++) {
    promises.push($.ajax(...));
}
$.when.apply($, promises).then(function() {
    // returned data is in arguments[0][0], arguments[1][0], ... arguments[9][0]
    // you can process it here
}, function() {
    // error occurred
});

ES6 স্ট্যান্ডার্ড প্রতিশ্রুতি

কেবিএর উত্তরে যেমন উল্লেখ করা হয়েছে : আপনার যদি অভ্যন্তরীণ প্রতিশ্রুতিগুলি অন্তর্নির্মিত (আধুনিক ব্রাউজার বা নোড.জেএস বা ব্যাবেলজ ট্রান্সপাইল ব্যবহার করে বা একটি প্রতিশ্রুতি পলফিল ব্যবহার করে) পরিবেশ থাকে তবে আপনি ES6- নির্দিষ্ট প্রতিশ্রুতি ব্যবহার করতে পারেন। ব্রাউজার সমর্থনের জন্য এই টেবিলটি দেখুন । প্রতিশ্রুতিগুলি IE বাদে বেশ কয়েকটি বর্তমান ব্রাউজারগুলিতে সমর্থিত।

যদি doAjax()কোনও প্রতিশ্রুতি দেয়, তবে আপনি এটি করতে পারেন:

var promises = [];
for (var i = 0; i < 10; i++) {
    promises.push(doAjax(...));
}
Promise.all(promises).then(function() {
    // returned data is in arguments[0], arguments[1], ... arguments[n]
    // you can process it here
}, function(err) {
    // error occurred
});

যদি আপনাকে কোনও প্রতিশ্রুতি ফেরত দেয় এমন একটি অ-প্রতিশ্রুতি অ্যাসিঙ্ক অপারেশন করার দরকার হয় তবে আপনি এটি "প্রতিশ্রুতি" দিতে পারেন:

function doAjax(...) {
    return new Promise(function(resolve, reject) {
        someAsyncOperation(..., function(err, result) {
            if (err) return reject(err);
            resolve(result);
        });
    });
}

এবং, তারপরে উপরের প্যাটার্নটি ব্যবহার করুন:

var promises = [];
for (var i = 0; i < 10; i++) {
    promises.push(doAjax(...));
}
Promise.all(promises).then(function() {
    // returned data is in arguments[0], arguments[1], ... arguments[n]
    // you can process it here
}, function(err) {
    // error occurred
});

ব্লুবার্ড প্রতিশ্রুতি

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

 var doAjax = Promise.promisify(someAsync);
 var someData = [...]
 Promise.map(someData, doAjax).then(function(results) {
     // all ajax results here
 }, function(err) {
     // some error here
 });

4
@ কেবিএ - সমস্ত কৌশলগুলি এখনও প্রযোজ্য হওয়ায় আমি এই উত্তরটিকে পুরানো বলেছিলাম না, বিশেষত যদি আপনি ইতিমধ্যে অ্যাজাক্সের জন্য jQuery ব্যবহার করছেন। কিন্তু, আমি স্থানীয় প্রতিশ্রুতি অন্তর্ভুক্ত করার জন্য এটি বেশ কয়েকটি উপায়ে আপডেট করেছি।
jفر00

আজকের দিনগুলিতে অনেকগুলি ক্লিনার সমাধান রয়েছে যার জন্য এমনকি জিকুরির দরকার নেই। আমি এটি ফেচাপিআই এবং প্রতিশ্রুতি দিয়ে করছি
philx_x

@ ফিলিল্ড_এক্স - আপনি আইই এবং সাফারি সমর্থন সম্পর্কে কী করছেন?
jਫਰ00

@ jender00 গিথুব একটি পলিফিল github.com/github/fetch তৈরি করেছেন । বা আমি নিশ্চিত নই যে বাবেল এখনও আনতে সহায়তা করে। babeljs.io
philx_x

@ ফিল্ম_এক্স - তাই ভেবেছিলেন। আজকাল আনতে ব্যবহারের জন্য আপনার একটি পলিফিল লাইব্রেরি প্রয়োজন। একটি এজ্যাক্স লাইব্রেরি এড়ানো সম্পর্কে আপনার মন্তব্য থেকে কিছুটা বাতাস নেয়। আনয়নটি দুর্দান্ত, তবে এটি কোনও পলিফিল ছাড়াই ব্যবহার করতে সক্ষম হওয়া থেকে বহু বছর দূরে। এটি এখনও সমস্ত ব্রাউজারের সর্বশেষতম সংস্করণে নেই। কর, এটি আমার উত্তরে আসলে কোনও পরিবর্তন করে না। আমার কাছে একটি ছিল doAjax()যা বিকল্পগুলির মধ্যে একটি হিসাবে প্রতিশ্রুতি দেয়। একই জিনিস fetch()
jਫਰ00

17

2015 থেকে চেক করা হচ্ছে: আমরা এখন নেটিভ প্রতিশ্রুতি মধ্যে সাম্প্রতিকতম ব্রাউজার (এজ 12, ফায়ারফক্স 40, ক্রোম 43, সাফারি 8, অপেরা 32 এবং অ্যান্ড্রয়েড ব্রাউজার 4.4.4 এবং iOS সাফারি 8.4, কিন্তু না ইন্টারনেট এক্সপ্লোরার, অপেরা মিনি আর পুরোনো সংস্করণগুলি Android এর)।

যদি আমরা 10 টি এসিঙ্ক ক্রিয়া করতে এবং সেগুলি শেষ হয়ে গেলে বিজ্ঞপ্তি পেতে চাই তবে আমরা Promise.allকোনও বাহ্যিক লাইব্রেরি ছাড়াই নেটিভ ব্যবহার করতে পারি :

function asyncAction(i) {
    return new Promise(function(resolve, reject) {
        var result = calculateResult();
        if (result.hasError()) {
            return reject(result.error);
        }
        return resolve(result);
    });
}

var promises = [];
for (var i=0; i < 10; i++) {
    promises.push(asyncAction(i));
}

Promise.all(promises).then(function AcceptHandler(results) {
    handleResults(results),
}, function ErrorHandler(error) {
    handleError(error);
});

4
Promises.all()হওয়া উচিত Promise.all()
jفر00

4
আপনার উত্তরে আপনাকে কোন ব্রাউজারগুলি ব্যবহার করতে পারবেন সেগুলিতেও উল্লেখ করতে হবে Promise.all()যার মধ্যে আইই এর কোনও বর্তমান সংস্করণ নেই।
jفر00

10

আপনি কখন পদ্ধতির সাথে jQuery এর ডিফার্ড অবজেক্টটি ব্যবহার করতে পারেন ।

deferredArray = [];
forloop {
    deferred = new $.Deferred();
    ajaxCall(function() {
      deferred.resolve();
    }
    deferredArray.push(deferred);
}

$.when(deferredArray, function() {
  //this code is called after all the ajax calls are done
});

7
প্রশ্নটি ট্যাগ করা jQueryহয়নি যার জন্য সাধারণত ওপি কোনও jQuery উত্তর চায় না।
jender00

8
@ jfriend00 আমি যখন চাকাটি ইতিমধ্যে jQuery এ তৈরি করা হয়েছিল তখন পুনরায় উদ্ভাবন করতে চাইনি
পল

4
@ পল এর পরিবর্তে আপনার চাকাটিকে পুনরায় উদ্ভাবন করুন যাতে আপনার 40kb জাঙ্ক সহ কিছু সাধারণ (পিছিয়ে দেওয়া) করা যায়
রায়নস

4
তবে সকলেই jQuery এবং এসওতে এখানে কাস্টমটি ব্যবহার করতে বা করতে চায় না তা হ'ল আপনি ইঙ্গিত করেছেন যে আপনি আপনার প্রশ্নটি jQuery এর সাথে ট্যাগ করেছেন কিনা।
jfriend00

4
$ .যখন কলটি এই উদাহরণটি ভুল। স্থগিত / প্রতিশ্রুতির একটি অ্যারের জন্য অপেক্ষা করতে আপনাকে $ .When.apply (promises, প্রতিশ্রুতি) ব্যবহার করতে হবে। তবু (ফাংশন () {/ * ডু স্টাফ * /}) করুন।
টানুন

9

আপনি এটির মতো অনুকরণ করতে পারেন:

  countDownLatch = {
     count: 0,
     check: function() {
         this.count--;
         if (this.count == 0) this.calculate();
     },
     calculate: function() {...}
  };

তারপরে প্রতিটি অ্যাসিঙ্ক কল এটি করে:

countDownLatch.count++;

প্রতিটি অ্যাসিঞ্চে মেথডের শেষে ফিরে যাওয়ার সময় আপনি এই লাইনটি যুক্ত করেন:

countDownLatch.check();

অন্য কথায়, আপনি একটি গণনা-ডাউন-ল্যাচ কার্যকারিতা অনুকরণ করুন।


সমস্ত ব্যবহারের 99% ক্ষেত্রে একটি প্রতিশ্রুতি হ'ল উপায় তবে আমি এই উত্তরটি পছন্দ করি কারণ এটি এমন পরিস্থিতিতে অ্যা্যাসিঙ্ক কোড পরিচালনা করার একটি পদ্ধতি চিত্রিত করে যেখানে কোনও প্রতিশ্রুতি পলফিল বড় জেএস পরে এটি ব্যবহার করে!
সুকিমা

6

এটি আমার মতে সর্বাধিক ঝরঝরে উপায়।

প্রতিশ্রুতি

ফেচাপি

(কোনও কারণে অ্যারে.ম্যাপ ভিতরে কাজ করে না। তবে আমার জন্য কাজ করে But

Promise.all([
  fetch('/user/4'),
  fetch('/user/5'),
  fetch('/user/6'),
  fetch('/user/7'),
  fetch('/user/8')
]).then(responses => {
  return responses.map(response => {response.json()})
}).then((values) => {
  console.log(values);
})

4
আমি মনে করি এটি হওয়া দরকার return responses.map(response => { return response.json(); }), বা return responses.map(response => response.json())

1

মত একটি নিয়ন্ত্রণ প্রবাহ লাইব্রেরি ব্যবহার করুন after

after.map(array, function (value, done) {
    // do something async
    setTimeout(function () {
        // do something with the value
        done(null, value * 2)
    }, 10)
}, function (err, mappedArray) {
    // all done, continue here
    console.log(mappedArray)
})
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.