Node.js या जावास्क्रिप्ट में सिंक फ़ंक्शन में async फ़ंक्शन कॉल को कैसे लपेटें?


122

मान लीजिए कि आप एक पुस्तकालय बनाए रखते हैं जो एक फ़ंक्शन को उजागर करता है getData। आपके उपयोगकर्ता इसे वास्तविक डेटा प्राप्त करने के लिए कहते हैं:
var output = getData();
हुड डेटा के तहत एक फ़ाइल में सहेजा जाता है ताकि आपने getDataNode.js अंतर्निहित का उपयोग करके कार्यान्वित किया fs.readFileSync। यह दोनों स्पष्ट है getDataऔर fs.readFileSyncसिंक कार्य हैं। एक दिन आपको बताया गया था कि अंतर्निहित डेटा स्रोत को मोंगोडीबी जैसे रेपो में बदल दिया जाए जिसे केवल अतुल्यकालिक रूप से एक्सेस किया जा सकता है। आपको अपने उपयोगकर्ताओं को पेशाब करने से बचने के लिए भी कहा गया था, getDataकेवल एक वादा वापस करने या कॉलबैक पैरामीटर की मांग करने के लिए एपीआई को नहीं बदला जा सकता है। आप दोनों आवश्यकताओं को कैसे पूरा करते हैं?

कॉलबैक / वादे का उपयोग करते हुए अतुल्यकालिक कार्य JavasSript और Node.js. का डीएनए है किसी भी गैर-तुच्छ जेएस एप्लिकेशन को शायद इस कोडिंग शैली के साथ अनुमति दी जाती है। लेकिन यह अभ्यास आसानी से तथाकथित कॉलबैक पिरामिड को जन्म दे सकता है। इससे भी बदतर, अगर कॉल श्रृंखला में किसी भी कॉलर में कोई भी कोड async फ़ंक्शन के परिणाम पर निर्भर करता है, तो उन कोड को कॉलबैक फ़ंक्शन में भी लपेटना पड़ता है, साथ ही कॉलर पर एक कोडिंग शैली की बाधा भी होती है। समय-समय पर मुझे बड़े पैमाने पर वैश्विक पुन: फैक्टरिंग से बचने के लिए एक सिंक फ़ंक्शन में एक async फ़ंक्शन (अक्सर एक 3 पार्टी लाइब्रेरी में प्रदान किया गया) को इनकैप्सुलेट करने की आवश्यकता मिलती है। इस विषय पर समाधान की खोज आमतौर पर नोड फाइबर्स के साथ समाप्त हुईया npm संकुल इससे प्राप्त होता है। लेकिन फाइबर सिर्फ उस समस्या को हल नहीं कर सकते हैं जिसका मैं सामना कर रहा हूं। यहां तक ​​कि फाइबर्स लेखक द्वारा प्रदान किए गए उदाहरण ने कमी को चित्रित किया:

...
Fiber(function() {
    console.log('wait... ' + new Date);
    sleep(1000);
    console.log('ok... ' + new Date);
}).run();
console.log('back in main');

वास्तविक उत्पादन:

wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
back in main
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)

यदि फ़ंक्शन फाइबर वास्तव में async फ़ंक्शन नींद को सिंक में बदल देता है, तो आउटपुट होना चाहिए:

wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
back in main

मैंने JSFiddle में एक और सरल उदाहरण बनाया है और अपेक्षित उत्पादन प्राप्त करने के लिए कोड की तलाश कर रहा हूं । मैं एक समाधान स्वीकार करूंगा जो केवल Node.js में काम करता है इसलिए आप JSFiddle में काम नहीं करने के बावजूद किसी भी npm पैकेज की आवश्यकता के लिए स्वतंत्र हैं।


2
Async फ़ंक्शन को नोड में सिंक्रोनस कभी नहीं बनाया जा सकता है, और यहां तक ​​कि अगर वे कर सकते हैं, तो आपको नहीं करना चाहिए। समस्या ऐसी है कि fs मॉड्यूल में आप फ़ाइल सिस्टम के लिए सिंक्रोनस और एसिंक्रोनस एक्सेस के लिए पूरी तरह से अलग-अलग फ़ंक्शन देख सकते हैं। आप जो सबसे अच्छा कर सकते हैं वह वादे या कोरआउट (ईएस 6 में जनरेटर) के साथ एसिंक्स की उपस्थिति को मुखौटा है। कॉलबैक पिरामिड के प्रबंधन के लिए, फ़ंक्शन कॉल में परिभाषित करने के बजाय उन्हें नाम दें, और async लाइब्रेरी जैसी किसी चीज़ का उपयोग करें।
qubyte

8
Dandavis करने के लिए, async बुलबुले को लागू करने के लिए विस्तार श्रृंखला, कभी कभी वैश्विक refactoring मजबूर। यह एक जटिल अनुप्रयोग के लिए हानिकारक और यहां तक ​​कि विनाशकारी है, जहां संशोधन और नियंत्रण महत्वपूर्ण है।
abbr

4
"कयामत का कॉलबैक पिरामिड" केवल समस्या का प्रतिनिधित्व है। वादा इसे छिपा या प्रच्छन्न कर सकता है लेकिन सही चुनौती को संबोधित नहीं कर सकता है: यदि किसी एसिंक्स फ़ंक्शन का कॉलर एस्किंक फ़ंक्शन के परिणामों पर निर्भर करता है, तो उसे कॉलबैक का उपयोग करना होगा, और इसी तरह उसका कॉलर इत्यादि। यह बाधाओं को दूर करने का एक शास्त्रीय उदाहरण है। कार्यान्वयन विवरण के कारण फोन करने वाला।
abbr

1
@abbr: deasync मॉड्यूल के लिए धन्यवाद, आपकी समस्या का वर्णन वास्तव में वही है जो मैं खोज रहा हूं, और कोई समाधान योग्य समाधान नहीं मिल सका है। मैंने जनरेटर और पुनरावृत्तियों के साथ गड़बड़ की, लेकिन आप के समान निष्कर्ष पर आए।
केविन झांगियानी

2
यह ध्यान देने योग्य है कि यह एसिंक्स फ़ंक्शन को सिंक करने के लिए मजबूर करने के लिए लगभग एक अच्छा विचार नहीं है । आपके पास लगभग हमेशा एक बेहतर समाधान होता है जो समान प्रभाव (जैसे अनुक्रमण, चर सेटिंग, आदि) को प्राप्त करते हुए फ़ंक्शन के एसिंक्स-नेस को बरकरार रखता है।
मदारा का भूत

जवाबों:


104

deasync, async फ़ंक्शन को सिंक में बदल देता है, जिसे Node.js ईवेंट लूप को जावास्क्रिप्ट परत पर कॉल करके एक अवरुद्ध तंत्र के साथ कार्यान्वित किया जाता है। परिणामस्वरूप, deasync केवल बाद के कोड को पूरे थ्रेड को अवरुद्ध किए बिना चलाने से रोकता है, और न ही व्यस्त प्रतीक्षा को बढ़ाता है। इस मॉड्यूल के साथ, यहाँ jsFiddle चुनौती का जवाब दिया गया है:

function AnticipatedSyncFunction(){
  var ret;
  setTimeout(function(){
      ret = "hello";
  },3000);
  while(ret === undefined) {
    require('deasync').runLoopOnce();
  }
  return ret;    
}


var output = AnticipatedSyncFunction();
//expected: output=hello (after waiting for 3 sec)
console.log("output="+output);
//actual: output=hello (after waiting for 3 sec)

(अस्वीकरण: मैं इसका सह-लेखक हूं deasync। इस प्रश्न को पोस्ट करने के बाद मॉड्यूल बनाया गया था और कोई व्यावहारिक प्रस्ताव नहीं मिला।)


किसी और को इस के साथ किस्मत थी? मैं इसे काम नहीं कर सकता।
न्यूमैन

3
मैं इसे ठीक से काम नहीं कर सकता। आपको इस मॉड्यूल के लिए अपने दस्तावेज़ में सुधार करना चाहिए, यदि आप चाहते हैं कि इसका अधिक उपयोग हो। मुझे संदेह है कि लेखकों को ठीक से पता है कि मॉड्यूल का उपयोग करने के लिए क्या कर रहे हैं, और यदि वे करते हैं, तो वे निश्चित रूप से उन्हें दस्तावेज नहीं करते हैं।
अलेक्जेंडर मिल्स

5
अब तक जीथब इश्यू ट्रैकर में प्रलेखित एक पुष्ट समस्या है। समस्या को Node v0.12 में ठीक किया गया है। बाकी मैं जानता हूँ कि केवल आधारहीन अटकलें हैं जो दस्तावेज़ के लायक नहीं हैं। यदि आपको लगता है कि आपकी समस्या deasync की वजह से है, तो एक स्व-निहित, डुप्लिकेटेबल परिदृश्य पोस्ट करें और मैं इस पर ध्यान दूंगा।
abbr

मैंने इसका इस्तेमाल करने की कोशिश की और मुझे अपनी स्क्रिप्ट में कुछ सुधार मिले लेकिन फिर भी मुझे तारीख से कोई मतलब नहीं था। मैंने कोड को अनुसरण के रूप में संशोधित किया है: function AnticipatedSyncFunction(){ var ret; setTimeout(function(){ var startdate = new Date() //console.log(startdate) ret = "hello" + startdate; },3000); while(ret === undefined) { require('deasync').runLoopOnce(); } return ret; } var output = AnticipatedSyncFunction(); var startdate = new Date() console.log(startdate) console.log("output="+output); और मुझे दिनांक आउटपुट में अलग-अलग 3 सेकंड देखने की उम्मीद है!
एलेक्स

@abbr को ब्राउज़र और नोड निर्भरता के बिना उपयोग किया जा सकता है>
गांधी

5

एक npm सिंक मॉड्यूल भी है। जिसका उपयोग क्वेरी को निष्पादित करने की प्रक्रिया को सिंक्रनाइज़ करने के लिए किया जाता है।

जब आप समानांतर प्रश्नों को समकालिक तरीके से चलाना चाहते हैं, तो नोड ऐसा करने के लिए प्रतिबंधित करें क्योंकि यह कभी भी प्रतिक्रिया की प्रतीक्षा नहीं करता है। और सिंक मॉड्यूल उस तरह के समाधान के लिए बहुत सही है।

नमूना कोड

/*require sync module*/
var Sync = require('sync');
    app.get('/',function(req,res,next){
      story.find().exec(function(err,data){
        var sync_function_data = find_user.sync(null, {name: "sanjeev"});
          res.send({story:data,user:sync_function_data});
        });
    });


    /*****sync function defined here *******/
    function find_user(req_json, callback) {
        process.nextTick(function () {

            users.find(req_json,function (err,data)
            {
                if (!err) {
                    callback(null, data);
                } else {
                    callback(null, err);
                }
            });
        });
    }

संदर्भ लिंक: https://www.npmjs.com/package/sync


4

यदि फ़ंक्शन फाइबर वास्तव में async फ़ंक्शन नींद को सिंक में बदल देता है

हाँ। फाइबर के अंदर, फ़ंक्शन लॉगिंग से पहले इंतजार करता है ok। फाइबर एस्किंक फ़ंक्शंस को सिंक्रोनस नहीं बनाते हैं, लेकिन सिंक्रोनस-लुकिंग कोड लिखने की अनुमति देते हैं जो एसिंक्स फ़ंक्शंस का उपयोग करता है और फिर एसिंक्रोनस रूप से एक के अंदर चलेगा Fiber

समय-समय पर मुझे बड़े पैमाने पर वैश्विक पुन: फैक्टरिंग से बचने के लिए एक सिंक फ़ंक्शन में एक async फ़ंक्शन को एनक्रिप्ट करने की आवश्यकता होती है।

आप नहीं कर सकते। अतुल्यकालिक कोड को समकालिक बनाना असंभव है। आपको अपने वैश्विक कोड में यह अनुमान लगाने की आवश्यकता होगी, और इसे शुरू से ही async शैली में लिखें। चाहे आप एक फाइबर में वैश्विक कोड को लपेटें, वादों का उपयोग करें, जनरेटर का वादा करें, या साधारण कॉलबैक आपकी प्राथमिकताओं पर निर्भर करता है।

मेरा उद्देश्य कॉलर पर प्रभाव को कम करना है जब डेटा अधिग्रहण विधि को सिंक से बदलकर async किया जाता है

वादे और तंतु दोनों ऐसा कर सकते हैं।


1
यह ABSOLUTE सबसे खराब चीज है जिसे आप Node.js के साथ कर सकते हैं: "सिंक्रोनस-लुकिंग कोड जो एसिंक्स फ़ंक्शन का उपयोग करता है और फिर एसिंक्रोनस रूप से चलेगा।" यदि आपका API ऐसा करता है, तो आप जीवन बर्बाद कर देंगे। यदि यह अतुल्यकालिक है, तो इसे कॉलबैक की आवश्यकता होनी चाहिए, और यदि कॉलबैक प्रदान नहीं किया गया है तो त्रुटि को फेंक दें। जब तक आपका लक्ष्य लोगों को धोखा देना नहीं है, तब तक एपीआई बनाना सबसे अच्छा तरीका है।
अलेक्जेंडर मिल्स

@AlexMills: हाँ, यह वास्तव में भयानक होगा । हालाँकि, सौभाग्य से यह कुछ भी नहीं है जो एक एपीआई कर सकता है। एक अतुल्यकालिक एपीआई को हमेशा कॉलबैक स्वीकार करने / एक वादे को वापस करने / फाइबर के अंदर चलाने की उम्मीद करने की आवश्यकता होती है - यह बिना काम नहीं करता है। Afaik, तंतुओं का उपयोग ज्यादातर क्विक'डीथ तीस स्क्रिप्ट्स में किया गया था जो अवरुद्ध थे और कोई भी संगामिति नहीं थी, लेकिन वे एशियो एपीआई का उपयोग करना चाहते थे; जैसे नोड में कभी-कभी ऐसे मामले होते हैं जहां आप सिंक्रोनस fsविधियों का उपयोग करेंगे ।
बेर्गी

2
मुझे आमतौर पर नोड पसंद है। खासकर अगर मैं शुद्ध जेएस के बजाय टाइपस्क्रिप्ट का उपयोग कर सकता हूं। लेकिन यह पूरा async बकवास है कि आप जो कुछ भी करते हैं और शाब्दिक रूप से कॉल श्रृंखला में हर फ़ंक्शन को संक्रमित करता है जैसे ही आप एक एकल async कॉल करने का निर्णय लेते हैं वह कुछ है जो मैं वास्तव में ... वास्तव में नफरत करता हूं। Async api एक संक्रामक बीमारी की तरह है, एक कॉल आपके पूरे कोड आधार को संक्रमित करता है जो आपको आपके सभी कोड को फिर से लिखने के लिए मजबूर करता है। मैं वास्तव में यह नहीं समझता कि कोई भी कैसे तर्क दे सकता है कि यह अच्छी बात है।
Kris

@ क्रिस नोड IO कार्यों के लिए एक अतुल्यकालिक मॉडल का उपयोग करता है क्योंकि यह तेज और सरल है। आप कई चीजें समकालिक रूप से भी कर सकते हैं, लेकिन ब्लॉकिंग धीमी है क्योंकि आप समवर्ती कुछ भी नहीं कर सकते - जब तक कि आप थ्रेड्स के लिए नहीं जाते हैं, जो सब कुछ जटिल बनाते हैं।
बरगी

@ बर्गी मैंने घोषणा पत्र पढ़ा इसलिए मुझे तर्क पता हैं। लेकिन अपने मौजूदा कोड को async में बदलते हुए जिस क्षण आपने हिट किया, वह पहला एपीआई कॉल जिसमें कोई सिंक समतुल्य नहीं है सरल नहीं है। सब कुछ टूट जाता है और कोड की हर एक लाइन को जांचना पड़ता है। जब तक आपका कोड तुच्छ नहीं होता है, तो मैं गारंटी देता हूं ... पूरी चीज़ को एसिंक्स मुहावरे में बदलने के बाद इसे बदलने और फिर से काम करने में थोड़ा समय लगेगा।
क्रिश

2

आपको वादों का उपयोग करना है:

const asyncOperation = () => {
    return new Promise((resolve, reject) => {
        setTimeout(()=>{resolve("hi")}, 3000)
    })
}

const asyncFunction = async () => {
    return await asyncOperation();
}

const topDog = () => {
    asyncFunction().then((res) => {
        console.log(res);
    });
}

मुझे एरो फंक्शंस परिभाषाएँ अधिक पसंद हैं। लेकिन फॉर्म के किसी भी तार "() => {...}" को "फ़ंक्शन () {...}" के रूप में भी लिखा जा सकता है।

इसलिए asD फ़ंक्शन को कॉल करने के बावजूद टॉपडॉग async नहीं है।

यहां छवि विवरण दर्ज करें

संपादित करें: मुझे पता है कि एक सिंक फ़ंक्शन के अंदर एक async फ़ंक्शन को नियंत्रित करने के लिए आपको कई बार एक नियंत्रक के अंदर लपेटने की आवश्यकता होती है। उन स्थितियों के लिए, यहाँ एक पार्टी चाल है:

const getDemSweetDataz = (req, res) => {
    (async () => {
        try{
            res.status(200).json(
                await asyncOperation()
            );
        }
        catch(e){
            res.status(500).json(serviceResponse); //or whatever
        }
    })() //So we defined and immediately called this async function.
}

कॉलबैक के साथ इसका उपयोग करते हुए, आप एक रैप कर सकते हैं जो वादों का उपयोग नहीं करता है:

const asyncOperation = () => {
    return new Promise((resolve, reject) => {
        setTimeout(()=>{resolve("hi")}, 3000)
    })
}

const asyncFunction = async (callback) => {
    let res = await asyncOperation();
    callback(res);
}

const topDog = () => {
    let callback = (res) => {
        console.log(res);
    };

    (async () => {
        await asyncFunction(callback)
    })()
}

इस ट्रिक को EventEmitter पर लागू करके, आप एक ही परिणाम प्राप्त कर सकते हैं। EventEmitter के श्रोता को परिभाषित करें जहां मैंने कॉलबैक को परिभाषित किया है, और उस घटना का उत्सर्जन करें जहां मैंने कॉलबैक कहा था।


1

मुझे ऐसा परिदृश्य नहीं मिल रहा है जिसे नोड-फाइबर का उपयोग करके हल नहीं किया जा सकता है। नोड-फाइबर का उपयोग करके आपके द्वारा प्रदान किया गया उदाहरण अपेक्षा के अनुरूप व्यवहार करता है। कुंजी एक फाइबर के अंदर सभी प्रासंगिक कोड को चलाने के लिए है, इसलिए आपको यादृच्छिक पदों में एक नया फाइबर शुरू करने की आवश्यकता नहीं है।

एक उदाहरण देखते हैं: कहते हैं कि आप कुछ ढांचे का उपयोग करते हैं, जो आपके आवेदन का प्रवेश बिंदु है (आप इस ढांचे को संशोधित नहीं कर सकते हैं)। यह ढांचा नोडज मॉड्यूल को प्लगइन्स के रूप में लोड करता है, और प्लगइन्स पर कुछ तरीकों को कॉल करता है। आइए कहते हैं कि यह ढांचा केवल तुल्यकालिक कार्यों को स्वीकार करता है, और स्वयं फाइबर का उपयोग नहीं करता है।

एक पुस्तकालय है जिसे आप अपने किसी एक प्लग इन में उपयोग करना चाहते हैं, लेकिन यह पुस्तकालय async है, और आप इसे संशोधित भी नहीं करना चाहते हैं।

जब कोई फाइबर नहीं चल रहा हो तो मुख्य धागे का उत्पादन नहीं किया जा सकता है, लेकिन आप अभी भी फाइबर का उपयोग करके प्लगइन्स बना सकते हैं! बस एक आवरण प्रविष्टि बनाएं जो फाइबर के अंदर पूरे ढांचे को शुरू करता है, जिससे आप प्लगइन्स से निष्पादन प्राप्त कर सकते हैं।

नकारात्मक पक्ष: यदि ढांचा आंतरिक रूप से उपयोग setTimeoutया Promiseएस करता है , तो यह फाइबर संदर्भ से बच जाएगा। यह मजाक से चारों ओर से काम किया जा सकता है setTimeout, Promise.thenहै, और सभी ईवेंट हैंडलर्स।

तो यह है कि आप एक फाइबर Promiseहल कर सकते हैं जब तक कि एक हल नहीं होता है। यह कोड एक async (वादा वापसी) फ़ंक्शन लेता है और वादा हल होने पर फाइबर को फिर से शुरू करता है:

ढांचा-entry.js

console.log(require("./my-plugin").run());

async-lib.js

exports.getValueAsync = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve("Async Value");
    }, 100);
  });
};

मेरी-plugin.js

const Fiber = require("fibers");

function fiberWaitFor(promiseOrValue) {
  var fiber = Fiber.current, error, value;
  Promise.resolve(promiseOrValue).then(v => {
    error = false;
    value = v;
    fiber.run();
  }, e => {
    error = true;
    value = e;
    fiber.run();
  });
  Fiber.yield();
  if (error) {
    throw value;
  } else {
    return value;
  }
}

const asyncLib = require("./async-lib");

exports.run = () => {
  return fiberWaitFor(asyncLib.getValueAsync());
};

मेरी-entry.js

require("fibers")(() => {
  require("./framework-entry");
}).run();

जब आप चलाने node framework-entry.jsयह एक त्रुटि फेंक देगा: Error: yield() called with no fiber running। यदि आप node my-entry.jsइसे चलाते हैं तो यह अपेक्षित है।


0

डेटाबेस जैसे कुछ पहलुओं में Node.js कोड सिंक बनाना आवश्यक है। लेकिन Node.js का वास्तविक लाभ async कोड में है। चूंकि यह सिंगल थ्रेड नॉन-ब्लॉकिंग है।

हम महत्वपूर्ण कार्यक्षमता का उपयोग करके इसे सिंक कर सकते हैं। फिर कॉलबैक फ़ंक्शन को डेफर () के साथ बदलें।

सामान्य Async code.This कॉलबैक कार्यों का उपयोग करता है।

function add (var a, var b, function(err,res){
       console.log(res);
});

 function sub (var res2, var b, function(err,res1){
           console.log(res);
    });

 function div (var res2, var b, function(err,res3){
           console.log(res3);
    });

फाइबर (), वेट () और डेफर () का उपयोग करके उपरोक्त कोड को सिंक करें

fiber(function(){
     var obj1 = await(function add(var a, var b,defer()));
     var obj2 = await(function sub(var obj1, var b, defer()));
     var obj3 = await(function sub(var obj2, var b, defer()));

});

मुझे उम्मीद है कि इससे सहायता मिलेगी। धन्यवाद


0

आजकल यह जनरेटर पैटर्न कई स्थितियों में एक समाधान हो सकता है।

यहाँ अनुक्रमिक कंसोल का एक उदाहरण async readline.question फ़ंक्शन का उपयोग करके नोडज में संकेत देता है:

var main = (function* () {

  // just import and initialize 'readline' in nodejs
  var r = require('readline')
  var rl = r.createInterface({input: process.stdin, output: process.stdout })

  // magic here, the callback is the iterator.next
  var answerA = yield rl.question('do you want this? ', r=>main.next(r))    

  // and again, in a sync fashion
  var answerB = yield rl.question('are you sure? ', r=>main.next(r))        

  // readline boilerplate
  rl.close()

  console.log(answerA, answerB)

})()  // <-- executed: iterator created from generator
main.next()     // kick off the iterator, 
                // runs until the first 'yield', including rightmost code
                // and waits until another main.next() happens

-1

आपको यह नहीं देखना चाहिए कि कॉल के चारों ओर क्या होता है जो फाइबर बनाता है, बल्कि फाइबर के अंदर क्या होता है । एक बार जब आप फाइबर के अंदर होते हैं तो आप सिंक स्टाइल में प्रोग्राम कर सकते हैं। उदाहरण के लिए:

समारोह f1 () {
    कंसोल.लॉग ('प्रतीक्षा ...' + नई तिथि);
    नींद (1000);
    कंसोल.लॉग ('ठीक है ...' + नई तिथि);   
}

समारोह f2 () {
    f1 ();
    f1 ();
}

फाइबर (समारोह) ({
    f2 ();
})।Daud();

फाइबर के अंदर आप कॉल करते हैं f1, f2और sleepजैसे कि वे सिंक थे।

एक विशिष्ट वेब एप्लिकेशन में, आप अपने HTTP अनुरोध डिस्पैचर में फाइबर बनाएंगे। एक बार जब आप यह कर लेते हैं कि आप अपने सभी अनुरोधों को सिंक शैली में हैंडलिंग तर्क लिख सकते हैं, भले ही यह async फ़ंक्शन (fs, डेटाबेस, आदि) को कॉल करता हो।


धन्यवाद ब्रूनो। लेकिन क्या होगा अगर मुझे बूटस्ट्रैप कोड में सिंक स्टाइल की आवश्यकता होती है जो सर्वर को टीसीपी पोर्ट से बांधने से पहले निष्पादित करने की आवश्यकता होती है - जैसे कि कॉन्फ़िगरेशन या डेटा जिसे डीबी से पढ़ना पड़ता है जो कि एसिंक्स खोला जाता है? मैं फाइबर में पूरे server.js को लपेटने के साथ समाप्त हो सकता हूं, और मुझे संदेह है कि संपूर्ण प्रक्रिया स्तर पर संगामिति को मार देगा। फिर भी यह एक सुझाव है जो सत्यापित करने के लायक है। मेरे लिए आदर्श समाधान एक सिंक कॉल सिंटैक्स प्रदान करने के लिए एक async फ़ंक्शन को लपेटने में सक्षम होना चाहिए और प्रक्रिया स्तर पर संगामिति का त्याग किए बिना केवल कॉलर श्रृंखला में कोड की अगली पंक्तियों को ब्लॉक करता है।
abbr

आप अपने पूरे बूटस्ट्रैप कोड को एक बड़े फाइबर कॉल के अंदर लपेट सकते हैं। कोन्क्यूरिटी की समस्या नहीं होनी चाहिए क्योंकि बूटस्ट्रैप कोड को आमतौर पर पूरा करने से पहले आपको अनुरोधों को पूरा करने के लिए दौड़ना पड़ता है। इसके अलावा, एक फाइबर अन्य तंतुओं को चलने से नहीं रोकता है: हर बार जब आप एक उपज को मारते हैं तो आप अन्य तंतुओं (और मुख्य धागे) को चलाने का मौका देते हैं।
ब्रूनो जौहरी

मैंने फाइबर के साथ एक्सप्रेस बूटस्ट्रैप फ़ाइल server.js को लपेटा है। निष्पादन अनुक्रम वह है जिसे मैं ढूंढ रहा हूं, लेकिन उस लपेट का अनुरोध हैंडलर पर कोई प्रभाव नहीं पड़ता है। इसलिए मुझे लगता है कि EACH डिस्पैचर के लिए एक ही रैपर लगाना होगा। मैंने इस बिंदु को छोड़ दिया क्योंकि यह वैश्विक पुन: फैक्टरिंग से बचने में मदद करने के लिए कोई बेहतर काम नहीं करता है। मेरा उद्देश्य कॉलर पर प्रभाव को कम करना है जब डेटा अधिग्रहण विधि को सिंक से डीएओ लेयर में सिंक से बदल दिया जाता है और फाइबर अभी भी चुनौती के लिए थोड़ा छोटा है।
abbr

@fred: यह अनुरोध हैंडलर की तरह "स्ट्रीम सिंक्रनाइज़" करने के लिए बहुत मायने नहीं रखता है - आपको एक while(true) handleNextRequest()लूप की आवश्यकता होगी । एक फाइबर में प्रत्येक अनुरोध हैंडलर लपेटकर होगा।
बरगी

@fred: फाइबर एक्सप्रेस के साथ आपकी बहुत मदद नहीं करेगा क्योंकि एक्सप्रेस 'कॉलबैक एक निरंतरता कॉलबैक नहीं है (एक कॉलबैक जिसे हमेशा एक बार कहा जाता है, या तो त्रुटि के साथ या परिणाम के साथ)। लेकिन फाइबर कयामत के पिरामिड को हल करेंगे जब आपके पास निरंतर कॉलबैक (जैसे एफएस, मोंगोडब और अन्य बहुत से) के साथ async एपीआई के शीर्ष पर लिखे गए बहुत सारे कोड होंगे।
ब्रूनो जौहियर

-2

मैंने सबसे पहले नोड.जेएस के साथ संघर्ष किया और async.js सबसे अच्छा पुस्तकालय है जो मैंने आपको इससे निपटने में मदद करने के लिए पाया है। यदि आप नोड के साथ सिंक्रोनस कोड लिखना चाहते हैं, तो एप्रोच इस प्रकार है।

var async = require('async');

console.log('in main');

doABunchOfThings(function() {
  console.log('back in main');
});

function doABunchOfThings(fnCallback) {
  async.series([
    function(callback) {
      console.log('step 1');
      callback();
    },
    function(callback) {
      setTimeout(callback, 1000);
    },
    function(callback) {
      console.log('step 2');
      callback();
    },
    function(callback) {
      setTimeout(callback, 2000);
    },
    function(callback) {
      console.log('step 3');
      callback();
    },
  ], function(err, results) {
    console.log('done with things');
    fnCallback();
  });
}

यह कार्यक्रम हमेशा निम्नलिखित का उत्पादन करेगा ...

in main
step 1
step 2
step 3
done with things
back in main

2
asyncआपके उदाहरण b / c में यह mainकाम करता है, जो कॉलर की परवाह नहीं करता है। कल्पना करें कि आपके सभी कोड एक फ़ंक्शन में लिपटे हुए हैं जो कि आपके किसी async फ़ंक्शन कॉल के परिणाम को वापस करने वाला है। इसे आसानी console.log('return');से अपने कोड के अंत में जोड़कर काम नहीं करने का प्रमाण दिया जा सकता है । ऐसे मामले में आउटपुट पहले और returnबाद में होगा । in mainstep 1
abbr

-11

जावास्क्रिप्ट एक एकल लड़ी पिरोया भाषा है, आप अपने पूरे सर्वर को ब्लॉक नहीं करना चाहते हैं! Async कोड समाप्त करता है, निर्भरता स्पष्ट करके दौड़ की स्थिति।

अतुल्यकालिक कोड से प्यार करना सीखें!

promisesकॉलबैक नरक के पिरामिड बनाए बिना अतुल्यकालिक कोड के लिए एक नज़र है। मैं नोड.जेएस के लिए वादाक्यू लाइब्रेरी की सलाह देता हूं

httpGet(url.parse("http://example.org/")).then(function (res) {
    console.log(res.statusCode);  // maybe 302
    return httpGet(url.parse(res.headers["location"]));
}).then(function (res) {
    console.log(res.statusCode);  // maybe 200
});

http://howtonode.org/promises

संपादित करें: यह अब तक का मेरा सबसे विवादास्पद जवाब है, नोड में अब उपज कीवर्ड है, जो आपको एसिंक्स कोड का इलाज करने की अनुमति देता है जैसे कि यह साइक्रोनस था। http://blog.alexmaccaw.com/how-yield-will-transform-node


1
फ़ंक्शन को सिंक में बदलने के बजाय केवल कॉलबैक पैरामीटर को फिर से लिखें।
'17

2
yuu यह नहीं चाहते कि यह सिंक हो या आपका पूरा सर्वर ब्लॉक हो जाएगा! stackoverflow.com/questions/17959663/…
roo2

1
वांछनीय क्या अन्य घटनाओं को अवरुद्ध किए बिना एक सिंक कॉल है जैसे कि Node.js. परिभाषा के अनुसार एक सिंक फ़ंक्शन का अर्थ केवल यह है कि यह कॉल करने वाले तक वापस नहीं आएगा जब तक कि परिणाम उत्पन्न न हो (केवल एक वादा नहीं)। यह कॉल को अवरुद्ध करते समय अन्य घटनाओं को संभालने से सर्वर को पूर्व-बहिष्कृत नहीं करता है।
abbr

@ पसंदीदा: मुझे लगता है कि आप वादों की बात याद कर रहे हैं । वे बस एक पर्यवेक्षक पैटर्न अमूर्त नहीं हैं, लेकिन वे चेन को एक रास्ता प्रदान करते हैं और अतुल्यकालिक कार्यों की रचना करते हैं।
बरगी

1
@ बर्गी, मैं वादे का भरपूर इस्तेमाल करता हूं और जानता हूं कि वह क्या करता है। प्रभावी रूप से प्राप्त की गई यह एक एकल async फंक्शन इनवोकेशन को कई इनवोकेशन / स्टेटमेंट में तोड़ रही है। लेकिन यह परिणाम नहीं बदलता है - जब कॉलर लौटता है, तो वह async फ़ंक्शन का परिणाम नहीं लौटा सकता है। मैंने JSFiddle में पोस्ट किए गए उदाहरण को देखें। उस स्थिति में कॉल करने वाला फ़ंक्शन AnticipatedSyncFunction है और async फ़ंक्शन सेटटाइमआउट है। यदि आप वादे का उपयोग करके मेरी चुनौती का जवाब दे सकते हैं, तो कृपया मुझे दिखाएं।
abbr
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.