নোড.জেএস ব্যবহার করে কলব্যাক কল না করা পর্যন্ত কীভাবে কোনও ফাংশন অপেক্ষা করবেন


266

আমার একটি সরলীকৃত ফাংশন রয়েছে যা দেখতে এরকম দেখাচ্ছে:

function(query) {
  myApi.exec('SomeCommand', function(response) {
    return response;
  });
}

মূলত আমি এটি কল করতে myApi.execএবং কলব্যাক ল্যাম্বডায় প্রদত্ত প্রতিক্রিয়াটি ফিরিয়ে আনতে চাই। তবে উপরের কোডটি কাজ করে না এবং কেবল অবিলম্বে ফিরে আসে returns

খুব হ্যাকিশ প্রচেষ্টার জন্য, আমি নীচে চেষ্টা করেছিলাম যা কার্যকর হয়নি, তবে কমপক্ষে আপনি ধারণাটি পান যে আমি কী অর্জন করতে চাইছি:

function(query) {
  var r;
  myApi.exec('SomeCommand', function(response) {
    r = response;
  });
  while (!r) {}
  return r;
}

মূলত, এই সম্পর্কে যাওয়ার একটি ভাল 'নোড.জেএস / ইভেন্ট চালিত' উপায় কী? আমি চাই আমার ফাংশনটি কলব্যাকের কল না হওয়া পর্যন্ত অপেক্ষা করুন, তারপরে যে মানটি দেওয়া হয়েছিল তা ফিরিয়ে দিন।


3
বা আমি এখানে পুরোপুরি ভুল পথে চালিয়ে যাচ্ছি, এবং আমি কোনও প্রতিক্রিয়া ফেরানোর পরিবর্তে, অন্য কলব্যাক কল করব?
ক্রিস

এই আমার মতে সেরা তাই ব্যাখ্যা কেন ব্যস্ত লুপ কাজ করে না।
bluenote10

অপেক্ষা করার চেষ্টা করবেন না। কলব্যাকের শেষে নিজেই কেবল পরবর্তী ফাংশনটি (কলব্যাক-নির্ভর) কল করুন
অতুল

উত্তর:


282

"ভাল নোড.জেএস / ইভেন্ট চালিত" এটি করার উপায়টি অপেক্ষা না করা

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

function(query, callback) {
  myApi.exec('SomeCommand', function(response) {
    // other stuff here...
    // bla bla..
    callback(response); // this will "return" your value to the original caller
  });
}

সুতরাং আপনি এটি এর মতো ব্যবহার করবেন না:

var returnValue = myFunction(query);

তবে এটির মতো:

myFunction(query, function(returnValue) {
  // use the return value here instead of like a regular (non-evented) return value
});

5
ঠিকাছে দারুন. MyApi.exec কলব্যাক না বললে কী হবে? আমি এটি কীভাবে করব যাতে কলটিব্যাকটি 10 ​​বা সেকেন্ড পরে ত্রুটি মানের সাথে বলা হয় যা এটি আমাদের বা কিছু সময়সীমা বেঁধে দিয়েছিল?
ক্রিস

5
বা আরও ভাল (একটি চেক যোগ করা হয়েছে যাতে কলব্যাক দুইবার আহ্বান করা যায় না): jsfiddle.net/LdaFw/1
Jakob

148
এটি স্পষ্ট যে নোড / জেএসে নন-ব্লক করা মান, তবে অবশ্যই এমন সময় রয়েছে যখন ব্লক করা পছন্দ হয় (যেমন স্টিডিনে ব্লক করা)। এমনকি নোডের "ব্লকিং" পদ্ধতি রয়েছে (সমস্ত fs sync*পদ্ধতি দেখুন)। যেমন, আমি মনে করি এটি এখনও একটি বৈধ প্রশ্ন। ব্যস্ত অপেক্ষার থেকে বাদে নোডে ব্লকিং অর্জনের কি কোনও দুর্দান্ত উপায় আছে?
ntoodood

7
@Nategood এর মন্তব্যে দেরি করা উত্তর: আমি বেশ কয়েকটি উপায় নিয়ে ভাবতে পারি; এই মন্তব্যে ব্যাখ্যা করার জন্য খুব বেশি, তবে তাদের গুগল করুন। মনে রাখবেন নোড ব্লক করার জন্য তৈরি করা হয়নি, সুতরাং এগুলি নিখুঁত নয়। তাদের পরামর্শ হিসাবে ভাবেন। যাইহোক, এখানে যায়: (1) আপনার ফাংশনটি প্রয়োগ করতে সি ব্যবহার করুন এবং এটি ব্যবহারের জন্য এটি এনপিএম এ প্রকাশ করুন। syncপদ্ধতিগুলি এটাই করে । (২) ফাইবার, github.com/laverdet/node-fibers ব্যবহার করুন , (3) প্রতিশ্রুতি ব্যবহার করুন, উদাহরণস্বরূপ Q- গ্রন্থাগার, (4) জাভাস্ক্রিপ্টের শীর্ষে একটি পাতলা স্তর ব্যবহার করুন যা দেখতে অবরুদ্ধ দেখায়, তবে সংশ্লেষে সংকলিত হয়, মত maxtaco.github.com/coffee-script
জ্যাকব

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

45

এটি অর্জনের একটি উপায় হ'ল এপিআই কলটি প্রতিশ্রুতিতে গুটিয়ে রাখা এবং তারপরে ফলাফলটির awaitজন্য অপেক্ষা করা।

// let's say this is the API function with two callbacks,
// one for success and the other for error
function apiFunction(query, successCallback, errorCallback) {
    if (query == "bad query") {
        errorCallback("problem with the query");
    }
    successCallback("Your query was <" + query + ">");
}

// myFunction wraps the above API call into a Promise
// and handles the callbacks with resolve and reject
function apiFunctionWrapper(query) {
    return new Promise((resolve, reject) => {
        apiFunction(query,(successResponse) => {
            resolve(successResponse);
        }, (errorResponse) => {
            reject(errorResponse)
        });
    });
}

// now you can use await to get the result from the wrapped api function
// and you can use standard try-catch to handle the errors
async function businessLogic() {
    try {
        const result = await apiFunctionWrapper("query all users");
        console.log(result);

        // the next line will fail
        const result2 = await apiFunctionWrapper("bad query");
    } catch(error) {
        console.error("ERROR:" + error);
    }
}

// call the main function
businessLogic();

আউটপুট:

Your query was <query all users>
ERROR:problem with the query

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


10

আপনি যদি কল ব্যাক ব্যবহার করতে না চান তবে আপনি "কিউ" মডিউলটি ব্যবহার করতে পারেন।

উদাহরণ স্বরূপ:

function getdb() {
    var deferred = Q.defer();
    MongoClient.connect(databaseUrl, function(err, db) {
        if (err) {
            console.log("Problem connecting database");
            deferred.reject(new Error(err));
        } else {
            var collection = db.collection("url");
            deferred.resolve(collection);
        }
    });
    return deferred.promise;
}


getdb().then(function(collection) {
   // This function will be called afte getdb() will be executed. 

}).fail(function(err){
    // If Error accrued. 

});

আরও তথ্যের জন্য এটি উল্লেখ করুন: https://github.com/kriskowal/q


9

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

//initialize a global var to control the callback state
var callbackCount = 0;
//call the function that has a callback
someObj.executeCallback(function () {
    callbackCount++;
    runOtherCode();
});
someObj2.executeCallback(function () {
    callbackCount++;
    runOtherCode();
});

//call function that has to wait
continueExec();

function continueExec() {
    //here is the trick, wait until var callbackCount is set number of callback functions
    if (callbackCount < 2) {
        setTimeout(continueExec, 1000);
        return;
    }
    //Finally, do what you need
    doSomeThing();
}

5

দ্রষ্টব্য: এই উত্তরটি সম্ভবত উত্পাদন কোডে ব্যবহার করা উচিত নয়। এটি একটি হ্যাক এবং এর প্রভাব সম্পর্কে আপনার জানা উচিত।

সেখানে উভরুন মডিউল রয়েছে ( এখানে নতুন নোডেজ সংস্করণগুলির জন্য আপডেট হয়েছে ) যেখানে আপনি লিবুভের মূল ইভেন্ট লুপের (যা নোডেজের মূল লুপ) একক লুপটি কার্যকর করতে পারেন।

আপনার কোডটি দেখতে এই রকম হবে:

function(query) {
  var r;
  myApi.exec('SomeCommand', function(response) {
    r = response;
  });
  var uvrun = require("uvrun");
  while (!r)
    uvrun.runOnce();
  return r;
}

(আপনি বিকল্প ব্যবহার uvrun.runNoWait()করতে পারেন That এটি ব্লকিংয়ের সাথে কিছু সমস্যা এড়াতে পারে তবে 100% সিপিইউ লাগে takes)

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

আপনার কোডটিকে "ডান" করতে কীভাবে পুনরায় নকশা করবেন সে সম্পর্কে অন্যান্য উত্তরগুলি দেখুন।

আপনি যখন পরীক্ষা এবং এসএসপি করেন তখন এখানে এই সমাধানটি সম্ভবত কার্যকর। সিঙ্ক এবং সিরিয়াল কোড করতে চান।


5

নোড ৪.৮.০ থেকে আপনি জেনারেটর নামে পরিচিত ES6 এর বৈশিষ্ট্যটি ব্যবহার করতে পারবেন। গভীর ধারণার জন্য আপনি এই নিবন্ধটি অনুসরণ করতে পারেন । তবে মূলত আপনি জেনারেটর এবং এই কাজটি সম্পন্ন করার প্রতিশ্রুতি ব্যবহার করতে পারেন। আমি জেনারেটরের প্রচার এবং পরিচালনা করতে ব্লুবার্ড ব্যবহার করছি ।

আপনার কোডটি নীচের উদাহরণের মতো সূক্ষ্ম হওয়া উচিত।

const Promise = require('bluebird');

function* getResponse(query) {
  const r = yield new Promise(resolve => myApi.exec('SomeCommand', resolve);
  return r;
}

Promise.coroutine(getResponse)()
  .then(response => console.log(response));

1

মনে করুন আপনার একটি ফাংশন রয়েছে:

var fetchPage(page, callback) {
   ....
   request(uri, function (error, response, body) {
        ....
        if (something_good) {
          callback(true, page+1);
        } else {
          callback(false);
        }
        .....
   });


};

আপনি এইভাবে কলব্যাকগুলি ব্যবহার করতে পারেন:

fetchPage(1, x = function(next, page) {
if (next) {
    console.log("^^^ CALLBACK -->  fetchPage: " + page);
    fetchPage(page, x);
}
});

-1

এটি আইও-অবরুদ্ধকরণের উদ্দেশ্যকে পরাস্ত করে - যখন এটির ব্লকিংয়ের প্রয়োজন হয় না তখন আপনি এটি ব্লক করছেন :)

নোড.জেএসকে অপেক্ষা করতে বাধ্য করার পরিবর্তে আপনার কলব্যাকগুলি বাসা বাঁধানো উচিত বা কলব্যাকের ভিতরে যেখানে আপনাকে ফলাফলের প্রয়োজন সেখানে অন্য কলব্যাক কল করা উচিত r

সম্ভাবনাগুলি হ'ল, যদি আপনাকে বাধ্যতামূলক অবরুদ্ধ করার প্রয়োজন হয় তবে আপনি আপনার স্থাপত্য সম্পর্কে ভুল চিন্তা করছেন।


আমার সন্দেহ ছিল আমার প্রায় পিছনের দিকে এটি ছিল।
ক্রিস

31
সম্ভাবনাগুলি হ'ল, আমি কেবল http.get()কয়েকটি URL এবং console.log()এর সামগ্রীতে একটি দ্রুত স্ক্রিপ্ট লিখতে চাই । নোডে তা করতে আমাকে পিছন দিকে ঝাঁপিয়ে পড়তে হবে কেন?
ড্যান ড্যাসক্লেস্কু

6
@ ড্যানডাসকলেস্কু: এবং স্থির ভাষায় এটি করার জন্য আমাকে কেন স্বাক্ষরগুলি প্রকারের ঘোষণা করতে হবে? এবং কেন আমাকে সি-জাতীয় ভাষায় এটি একটি মূল পদ্ধতিতে রাখতে হবে? এবং কেন আমাকে এটি সংকলিত ভাষায় সংকলন করতে হবে? আপনি যা জিজ্ঞাসা করছেন তা নোড.জেএস-এর একটি মৌলিক নকশার সিদ্ধান্ত is এই সিদ্ধান্তের পক্ষে মতামত রয়েছে। আপনি যদি এটি পছন্দ না করেন তবে আপনি অন্য একটি ভাষা ব্যবহার করতে পারেন যা আপনার স্টাইলটি আরও ভাল ফিট করে। এজন্য আমাদের একের অধিক রয়েছে।
Jakob

@ জ্যাকব: আপনার তালিকাভুক্ত সমাধানগুলি প্রকৃতপক্ষে উপশমী। এর অর্থ এই নয় যে ভাল নেই, যেমন মেটিয়ারের ফাইবারগুলিতে নোডের সার্ভার-সাইড ব্যবহার, যা কলব্যাক হেল সমস্যাটি দূর করে।
ড্যান ড্যাসক্লেস্কু

13
@ জাকোব: "বাস্তুসংস্থান এক্স কেন সাধারণ কাজ Y এর অকারণে কঠিন করে তোলে?" এর সেরা উত্তর যদি? "যদি আপনি এটি পছন্দ করেন না, বাস্তুতন্ত্র এক্স ব্যবহার করবেন না", তবে এটি একটি শক্তিশালী লক্ষণ যে বাস্তুতন্ত্র এক্স এর ডিজাইনার এবং রক্ষণাবেক্ষণকারীরা তাদের বাস্তুতন্ত্রের প্রকৃত ব্যবহারের তুলনায় তাদের নিজস্ব ইওলোকে অগ্রাধিকার দিচ্ছেন। আমার অভিজ্ঞতাটি হয়েছে যে নোড সম্প্রদায় (রুবি, এলিক্সির এবং এমনকি পিএইচপি সম্প্রদায়ের বিপরীতে) সাধারণ কাজগুলিকে কঠিন করে তোলার উপায় থেকে বেরিয়ে যায়। আপনাকে সেই অ্যান্টিপ্যাটার্নের জীবন্ত উদাহরণ হিসাবে উপস্থাপনের জন্য অনেক ধন্যবাদ।
জাজ 21

-1

অ্যাসিঙ্ক ব্যবহার করা এবং এটি অপেক্ষা করা আরও অনেক সহজ।

router.post('/login',async (req, res, next) => {
i = await queries.checkUser(req.body);
console.log('i: '+JSON.stringify(i));
});

//User Available Check
async function checkUser(request) {
try {
    let response = await sql.query('select * from login where email = ?', 
    [request.email]);
    return response[0];

    } catch (err) {
    console.log(err);

  }

}

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