मैं जावास्क्रिप्ट में अतुल्यकालिक फ़ंक्शन कैसे बना सकता हूं?


143

इस कोड को देखें :

<a href="#" id="link">Link</a>
<span>Moving</span>

$('#link').click(function () {
    console.log("Enter");
    $('#link').animate({ width: 200 }, 2000, function() {
         console.log("finished");            
    });    
    console.log("Exit");    
});

जैसा कि आप कंसोल में देख सकते हैं, "चेतन" फ़ंक्शन अतुल्यकालिक है, और यह घटना हैंडलर ब्लॉक कोड के प्रवाह के लिए "कांटा" है। असल में :

$('#link').click(function () {
    console.log("Enter");
    asyncFunct();
    console.log("Exit");    
});

function asyncFunct() {
    console.log("finished");
}

ब्लॉक कोड के प्रवाह का पालन करें!

यदि मैं function asyncFunct() { }इस व्यवहार के साथ अपनी इच्छा बनाना चाहता हूं , तो मैं इसे जावास्क्रिप्ट / jquery के साथ कैसे कर सकता हूं? मुझे लगता है कि के उपयोग के बिना एक रणनीति है setTimeout()


jQuery के स्रोतों पर एक नज़र डालें :)
yatskevich

.Animate () मैथोड एक कॉलबैक का उपयोग करता है। एनीमेशन पूरा होने पर चेतन कॉलबैक करेगा। यदि आपको (.animate) के समान व्यवहार की आवश्यकता है, तो आपको कॉलबैक की आवश्यकता है (कुछ अन्य कार्यों के बाद "मुख्य" फ़ंक्शन द्वारा कहा जाता है)। यदि आपको एक "पूर्ण" async फ़ंक्शन (निष्पादन प्रवाह को रोकने के साथ एक फ़ंक्शन कहा जाता है) की आवश्यकता है तो यह अलग है। इस स्थिति में आप लगभग 0 विलंब के साथ setTimeout () का उपयोग कर सकते हैं।
Fabio Buda

@ फैबियो बडा: कॉलबैक () में एक प्रकार का एसिंक्स क्यों लगाया जाना चाहिए? वास्तव में, यह jsfiddle.net/5H9XT/9
markzzz

वास्तव में "कॉलबैक" के बाद मैंने सेटटाइमआउट के साथ एक "पूर्ण" एसिंक्स विधि का हवाला दिया। मेरा मतलब है कि अन्य कोड के बाद फ़ंक्शन को कॉल करने के तरीके में छद्म-एस्किंट के रूप में कॉलबैक :-)
Fabio Buda

जवाबों:


185

आप वास्तव में कस्टम अतुल्यकालिक फ़ंक्शन नहीं कर सकते। आपको अंततः मूल रूप से प्रदान की गई तकनीक पर लाभ उठाना होगा, जैसे:

  • setInterval
  • setTimeout
  • requestAnimationFrame
  • XMLHttpRequest
  • WebSocket
  • Worker
  • कुछ HTML5 एपीआई जैसे फ़ाइल एपीआई, वेब डेटाबेस एपीआई
  • तकनीकें जो समर्थन करती हैं onload
  • ... कई अन्य

वास्तव में, एनीमेशन के लिए jQuery का उपयोग करता है setInterval


1
मैं कल एक मित्र के साथ इस पर चर्चा कर रहा था इसलिए यह उत्तर एकदम सही है! मैं समझता हूं और async फ़ंक्शंस की पहचान कर सकते हैं और उन्हें JS में ठीक से उपयोग कर सकते हैं। लेकिन बस हम कस्टम क्यों लागू नहीं कर सकते हैं मेरे लिए स्पष्ट नहीं है। यह एक ब्लैक बॉक्स की तरह है जिसे हम जानते हैं कि यह कैसे काम करता है (उपयोग करते हैं, कहते हैं setInterval) , लेकिन हम यह भी नहीं खोल सकते कि यह कैसे किया जाए। क्या आपको इस विषय पर अधिक जानकारी है?
मैथ्यू फेलिप

2
@MatheusFelipe वे फ़ंक्शंस जावास्क्रिप्ट इंजन के कार्यान्वयन के मूल निवासी हैं और केवल एक चीज जिस पर आप भरोसा कर सकते हैं, वह है एचटीएमएल 5 टाइमर्स और ब्लैक बॉक्स प्रकृति पर भरोसा है कि वे चश्मे के अनुसार व्यवहार करते हैं।
शाम

10
@MatheusFelipe youtu.be/8aGhZQkoFbQ इस विषय के बारे में अब तक की सबसे अच्छी बात ...
एंड्रियास नीडेर्मेयर

कुछ implemantations, विशेष रूप से Node.js में, समर्थनsetImmediate
जॉन सुरेल

किस बारे में promises। क्या यह एक देता है awaitable?
नितिन चंद्रन

69

आप एक टाइमर का उपयोग कर सकते हैं:

setTimeout( yourFn, 0 );

( yourFnआपके फ़ंक्शन का संदर्भ कहां है)

या, लोदश के साथ :

_.defer( yourFn );

funcमौजूदा कॉल स्टैक को साफ़ करने तक डिफोकस नहीं होता। funcइसे लागू करने पर कोई अतिरिक्त तर्क दिए जाते हैं ।


3
यह काम नहीं करता है, मेरा जावास्क्रिप्ट फ़ंक्शन जो एक कैनवास में खींचता है वह UI को प्रतिक्रिया नहीं देता है।
गाब ०६

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

लिंक टूट गया है।
जूलियनसोटो

1
@ जूलियनसोटो तय
ul

1
setTimeoutHTML5 युक्ति द्वारा न्यूनतम समय 4 मिलीसेकंड है। इसे देते हुए 0 को अभी भी न्यूनतम समय लगेगा। लेकिन हाँ, यह एक समारोह deferrer के रूप में अच्छी तरह से काम करता है।
हेजज

30

यहाँ आपके पास सरल समाधान है (इसके बारे में अन्य लिखें) http://www.benlesh.com/2012/05/calling-javascript-factंक्शन

और यहाँ आपके पास तैयार समाधान है:

function async(your_function, callback) {
    setTimeout(function() {
        your_function();
        if (callback) {callback();}
    }, 0);
}

परीक्षण 1 ( '1 x 2 3' या '1 2 x 3' या '1 2 3 x' ) का उत्पादन कर सकता है:

console.log(1);
async(function() {console.log('x')}, null);
console.log(2);
console.log(3);

परीक्षण 2 ( हमेशा 'x 1' का उत्पादन करेगा ):

async(function() {console.log('x');}, function() {console.log(1);});

इस फ़ंक्शन को टाइमआउट 0 से निष्पादित किया जाता है - यह अतुल्यकालिक कार्य का अनुकरण करेगा


6
TEST 1 वास्तव में कभी भी केवल '1 2 3 x' आउटपुट कर सकता है और TEST 2 को हर बार '1 x' आउटपुट की गारंटी दी जाती है। TEST 2 में अप्रत्याशित परिणामों का कारण console.log(1)यह है कि कहा जाता है और आउटपुट ( undefined) 2 तर्क के रूप में पारित किया जाता है async()। टेस्ट 1 के मामले में, मुझे लगता है कि आप जावास्क्रिप्ट की निष्पादन कतार को पूरी तरह से नहीं समझते हैं। क्योंकि एक console.log()ही स्टैक में होने वाली प्रत्येक कॉल , xअंतिम लॉग इन होने की गारंटी है। मैं गलत जवाब के लिए इस जवाब को वोट करूंगा लेकिन पर्याप्त प्रतिनिधि नहीं है।
जोशुआ पिकरी

1
@ जोशुआ: ऐसा लगता है कि @fider का मतलब TEST 2 को लिखना है async(function() {console.log('x')}, function(){console.log(1)});:।
nzn

@Nzn हाँ और @Joshua मैं मतलब TEST 2 as: async(function() {console.log('x')}, function(){console.log(1)});- मैं पहले से ही यह सही
fider

टेस्ट 2 आउटपुट 1 x है async (फ़ंक्शन () (setTimeout () => {कंसोल.लॉग ('x');}, 1000)}, फ़ंक्शन () {कंसोल.लॉग (1);});
मोहसिन

10

यहां एक फ़ंक्शन है जो किसी अन्य फ़ंक्शन में ले जाता है और एक ऐसे संस्करण को आउटपुट करता है जो async चलता है।

var async = function (func) {
  return function () {
    var args = arguments;
    setTimeout(function () {
      func.apply(this, args);
    }, 0);
  };
};

यह एक async फ़ंक्शन बनाने के लिए एक सरल तरीके के रूप में उपयोग किया जाता है:

var anyncFunction = async(function (callback) {
    doSomething();
    callback();
});

यह @ fider के उत्तर से भिन्न है क्योंकि फ़ंक्शन की अपनी संरचना है (कोई कॉलबैक नहीं जोड़ा गया है, यह फ़ंक्शन में पहले से ही है) और इसलिए भी कि यह एक नया फ़ंक्शन बनाता है जिसका उपयोग किया जा सकता है।


सेटटाइमआउट का उपयोग लूप में नहीं किया जा सकता है (अलग-अलग तर्कों के साथ एक ही फ़ंक्शन को कई बार कॉल करें)
user2284570

@ user2284570 यह क्या बंद करने के लिए कर रहे हैं। (function(a){ asyncFunction(a); })(a)
कुंडा

1
IIRC, आप इसे बिना किसी बंद के भी प्राप्त कर सकते हैं:setTimeout(asyncFunction, 0, a);
कुंडा

1
यदि async से हमारा तात्पर्य है: मुख्य थ्रेड के समानांतर पृष्ठभूमि में चलना, तो यह वास्तव में async नहीं है। यह सब करना होगा प्रक्रिया में निष्पादन में देरी है ।nextTick। आपके पास फ़ंक्शन में जो भी कोड है वह मुख्य थ्रेड पर निष्पादित होने वाला है। यदि फ़ंक्शन पीआई की गणना करने के लिए सेट किया गया था, तो ऐप को फ्रीआउट के साथ या उसके बिना फ्रीज किया जाएगा!
माइक एम

1
मुझे समझ नहीं आ रहा है कि यह उत्तर क्यों दिया गया है। जब मैं इसे अपने कोड में डालता हूं, तो फ़ंक्शन समाप्त होने तक प्रोग्राम ब्लॉक हो जाता है, जो वास्तव में ऐसा नहीं होना चाहिए ऐसा करना ।
मार्टिन अरगरामी

6

संपादित करें: मैंने प्रश्न को पूरी तरह से गलत समझा। ब्राउज़र में, मैं उपयोग करूँगा setTimeout। यदि यह महत्वपूर्ण था कि यह दूसरे धागे में चले, तो मैं वेब वर्कर्स का उपयोग करूंगा ।


1
? यह एक async फ़ंक्शन नहीं करता है: O
markzzz

6

देर से, लेकिन ईएस 6promises में उनके परिचय के बाद एक आसान समाधान दिखाने के लिए , यह अतुल्यकालिक कॉल को बहुत आसान तरीके से संभालता है:

आपने एक नए वादे में एसिंक्रोनस कोड निर्धारित किया है:

var asyncFunct = new Promise(function(resolve, reject) {
    $('#link').animate({ width: 200 }, 2000, function() {
        console.log("finished");                
        resolve();
    });             
});

resolve()जब async कॉल खत्म हो जाए तो सेट करने के लिए नोट करें।
फिर आप उस कोड को जोड़ते हैं जिसे आप .then()वादे के अंदर async कॉल खत्म होने के बाद चलाना चाहते हैं :

asyncFunct.then((result) => {
    console.log("Exit");    
});

यहाँ इसका एक टुकड़ा है:

$('#link').click(function () {
    console.log("Enter");
    var asyncFunct = new Promise(function(resolve, reject) {
        $('#link').animate({ width: 200 }, 2000, function() {
            console.log("finished");            	
            resolve();
        }); 			
    });
    asyncFunct.then((result) => {
        console.log("Exit");    
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#" id="link">Link</a>
<span>Moving</span>

या JSField


6

यह पृष्ठ आपको एक async जावास्क्रिप्ट फ़ंक्शन बनाने की मूल बातें के माध्यम से चलता है।

ES2017 के बाद से, अतुल्यकालिक javacript कार्यों को लिखना बहुत आसान है। आपको प्रॉमिस पर भी अधिक पढ़ना चाहिए ।


लिंक मर चुका है।
मार्टिन अरगरामी

3

यदि आप पैरामीटर्स का उपयोग करना चाहते हैं और आपके द्वारा बनाए गए एक साधारण एसक्यूएन कार्यकर्ता का उपयोग कर सकते हैं, तो अधिकतम संख्या में एस्किंक फ़ंक्शंस को विनियमित करें:

var BackgroundWorker = function(maxTasks) {
    this.maxTasks = maxTasks || 100;
    this.runningTasks = 0;
    this.taskQueue = [];
};

/* runs an async task */
BackgroundWorker.prototype.runTask = function(task, delay, params) {
    var self = this;
    if(self.runningTasks >= self.maxTasks) {
        self.taskQueue.push({ task: task, delay: delay, params: params});
    } else {
        self.runningTasks += 1;
        var runnable = function(params) {
            try {
                task(params);
            } catch(err) {
                console.log(err);
            }
            self.taskCompleted();
        }
        // this approach uses current standards:
        setTimeout(runnable, delay, params);
    }
}

BackgroundWorker.prototype.taskCompleted = function() {
    this.runningTasks -= 1;

    // are any tasks waiting in queue?
    if(this.taskQueue.length > 0) {
        // it seems so! let's run it x)
        var taskInfo = this.taskQueue.splice(0, 1)[0];
        this.runTask(taskInfo.task, taskInfo.delay, taskInfo.params);
    }
}

आप इसे इस तरह से उपयोग कर सकते हैं:

var myFunction = function() {
 ...
}
var myFunctionB = function() {
 ...
}
var myParams = { name: "John" };

var bgworker = new BackgroundWorker();
bgworker.runTask(myFunction, 0, myParams);
bgworker.runTask(myFunctionB, 0, null);

2
Function.prototype.applyAsync = function(params, cb){
      var function_context = this;
      setTimeout(function(){
          var val = function_context.apply(undefined, params); 
          if(cb) cb(val);
      }, 0);
}

// usage
var double = function(n){return 2*n;};
var display = function(){console.log(arguments); return undefined;};
double.applyAsync([3], display);

यद्यपि अन्य समाधानों की तुलना में मौलिक रूप से भिन्न नहीं है, मुझे लगता है कि मेरा समाधान कुछ अतिरिक्त अच्छी चीजें करता है:

  • यह कार्यों के मापदंडों के लिए अनुमति देता है
  • यह कॉलबैक में फ़ंक्शन का आउटपुट पास करता है
  • इसे Function.prototypeकॉल करने के लिए एक अच्छे तरीके से अनुमति देने के लिए जोड़ा जाता है

साथ ही, अंतर्निहित फ़ंक्शन की समानता Function.prototype.applyमुझे उचित लगती है।


1

@Pimvdb द्वारा शानदार जवाब के आगे, और बस मामले में जहां आप सोच रहे हैं, async.js वास्तव में अतुल्यकालिक कार्यों की पेशकश नहीं करता है। यहां लाइब्रेरी की मुख्य विधि का एक (बहुत) छीन लिया गया संस्करण है:

function asyncify(func) { // signature: func(array)
    return function (array, callback) {
        var result;
        try {
            result = func.apply(this, array);
        } catch (e) {
            return callback(e);
        }
        /* code ommited in case func returns a promise */
        callback(null, result);
    };
}

इसलिए फ़ंक्शन त्रुटियों से बचाता है और इनायत से इसे हैंडल करने के लिए कॉलबैक के लिए सौंप देता है, लेकिन कोड किसी अन्य जेएस फ़ंक्शन के समान ही समकालिक है।


1

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

नीचे दिए गए कोड में पृष्ठभूमि में कॉल करने के लिए फ़ंक्शन होता है async

Function.prototype.async = function(callback) {
    let blob = new Blob([ "self.addEventListener('message', function(e) { self.postMessage({ result: (" + this + ").apply(null, e.data) }); }, false);" ], { type: "text/javascript" });
    let worker = new Worker(window.URL.createObjectURL(blob));
    worker.addEventListener("message", function(e) {
        this(e.data.result);
    }.bind(callback), false);
    return function() {
        this.postMessage(Array.from(arguments));
    }.bind(worker);
};

यह उपयोग के लिए एक उदाहरण है:

(function(x) {
    for (let i = 0; i < 999999999; i++) {}
        return x * 2;
}).async(function(result) {
    alert(result);
})(10);

यह एक फ़ंक्शन को निष्पादित करता है जो forअतुल्यकालिकता के प्रदर्शन के रूप में समय लेने के लिए एक बड़ी संख्या के साथ पुनरावृति करता है , और फिर पारित संख्या का दोगुना हो जाता है। यह asyncविधि functionपृष्ठभूमि में वांछित फ़ंक्शन को कॉल करती है, और इसमें asyncकॉलबैक के पैरामीटर के रूप में प्रदान किया जाता है return। इसलिए कॉलबैक फ़ंक्शन में मैं alertपरिणाम देता हूं ।


0

MDN का सेटटाइमआउट संरक्षण "इस" के उपयोग पर एक अच्छा उदाहरण है

निम्नलिखित की तरह:

function doSomething() {
    // use 'this' to handle the selected element here
}

$(".someSelector").each(function() {
    setTimeout(doSomething.bind(this), 0);
});
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.