2011-11-03 12 views
17

तो, मैं एक मस्तिष्क टीज़र के बारे में सोच रहा हूं - अगर मेरे पास कोई बड़ी वस्तु थी तो मुझे किसी कारण से नोड जेएस में फिर से चलना पड़ा, और जब मैं ऐसा कर रहा था तो ईवेंट लूप को अवरुद्ध नहीं करना चाहता था?जावास्क्रिप्ट में लूप के लिए गैर-अवरोधन लिखने का सबसे साफ तरीका क्या है?

यहाँ एक ऑफ-द-टॉप ऑफ मेरे सिर उदाहरण है, मुझे यकीन है कि यह अधिक स्वच्छ हो सकता है कर रहा हूँ:

var forin = function(obj,callback){ 
    var keys = Object.keys(obj), 
     index = 0, 
     interval = setInterval(function(){ 
      if(index < keys.length){ 
       callback(keys[index],obj[keys[index]],obj); 
      } else { 
       clearInterval(interval); 
      } 
      index ++; 
     },0); 
} 

जबकि मुझे यकीन है कि वहाँ यह गंदा होने के लिए अन्य कारण हैं हूँ, यह लूप के लिए नियमित से धीमा निष्पादित करेगा, क्योंकि setInterval 0 वास्तव में हर 0 एमएस निष्पादित नहीं करता है, लेकिन मुझे यकीन नहीं है कि बहुत तेज प्रक्रिया के साथ लूप कैसे बनाना है .nextTick।

मेरे परीक्षणों में, मैंने पाया कि इस उदाहरण में 7 एमएस चलने लगते हैं, क्योंकि लूप के लिए देशी (हैऑनप्रॉपर्टी() चेक के साथ, एक ही जानकारी लॉगिंग), जो 4 एमएस लेता है।

तो, साफ/तेज़ तरीका यह एक ही कोड का उपयोग कर Node.js लिखने के लिए क्या है?

+0

क्षमा करें- प्रश्न – kennebec

+1

क्यों गलत करें? यह दुर्व्यवहार है। ऐसा मत करो – Raynos

+3

@ रेनोस - यह दुर्व्यवहार क्यों है? यदि मैं लूप के लिए मूल के साथ एक विशाल वस्तु के माध्यम से पुनरावृत्ति करता हूं, तो जब तक लूप निष्पादित होता है तब तक मैं थ्रेड को अवरुद्ध करता हूं। यह मुझे दुर्व्यवहार की तरह लगता है, अगर मैं हर उपयोगकर्ता की सेवा के लिए 25ms लेता हूं, जो एक विशाल स्केलिंग मुद्दे में अनुवाद कर सकता है। – Jesse

उत्तर

3

process.nextTick के व्यवहार बदल गया है के बाद से सवाल था पूछा। पिछले उत्तरों ने समारोह की सफाई और दक्षता के अनुसार प्रश्न का पालन नहीं किया।

// in node 0.9.0, process.nextTick fired before IO events, but setImmediate did 
// not yet exist. before 0.9.0, process.nextTick between IO events, and after 
// 0.9.0 it fired before IO events. if setImmediate and process.nextTick are 
// both missing fall back to the tick shim. 
var tick = 
    (root.process && process.versions && process.versions.node === '0.9.0') ? 
    tickShim : 
    (root.setImmediate || (root.process && process.nextTick) || tickShim); 

function tickShim(fn) {setTimeout(fn, 1);} 

// executes the iter function for the first object key immediately, can be 
// tweaked to instead defer immediately 
function asyncForEach(object, iter) { 
    var keys = Object.keys(object), offset = 0; 

    (function next() { 
    // invoke the iterator function 
    iter.call(object, keys[offset], object[keys[offset]], object); 

    if (++offset < keys.length) { 
     tick(next); 
    } 
    })(); 
} 

Kue और उचित काम कतार के बारे में @alessioalex's comments को ध्यान में रखना है।

यह भी देखें: share-time, एक मॉड्यूल जिसे मैंने मूल प्रश्न के इरादे के समान कुछ करने के लिए लिखा था।

+0

इस प्रश्न को नवीनतम जानकारी के साथ फिर से देखने के लिए अच्छा लगा। process.setImedimedi बनाम process.nextTick एक महत्वपूर्ण भेद है। धन्यवाद! – Jesse

+1

धन्यवाद, @ जेसे! ध्यान दें कि यह 'setImmediate' है, जैसे 'setInterval' या' setTimeout', 'process.setImmediate' नहीं। कोड स्निपेट में, मैं 'ReferenceError' से बचने के लिए' root.setImmediate' का उपयोग करता हूं। – skeggse

+1

ओह! आज सुबह मेरी कॉफी पीने की जरूरत है! – Jesse

-1

निम्नलिखित [ब्राउज़र] जावास्क्रिप्ट पर लागू होता है; यह node.js. के लिए पूरी तरह से अप्रासंगिक हो सकता है।


दो विकल्प मैं के बारे में पता:

  1. उपयोग एकाधिक टाइमर कतार कार्रवाई करने के लिए। वे बिछा होगा जो "अधिक बार प्रसंस्करण आइटम" का शुद्ध प्रभाव दे देंगे (यह भी अधिक CPU चोरी करने के लिए ;-) एक अच्छा तरीका है, या,
  2. चक्र के अनुसार अधिक काम करते हैं, या तो गिनती या समय आधारित।

मुझे यकीन है कि अगर वेब कर्मचारी लागू/उपलब्ध हैं नहीं कर रहा हूँ।

हैप्पी कोडिंग।

1

बहुत सी बातें यहाँ कहा जा करने के लिए कर रहे हैं।

  • यदि आपके पास उदाहरण के लिए एक वेब एप्लिकेशन है, तो आप उस एप्लिकेशन की प्रक्रिया में "भारी उठाने" नहीं करना चाहेंगे। भले ही आपका एल्गोरिदम कुशल है, फिर भी यह ऐप को धीमा कर देगा।
  • आप क्या हासिल करने की कोशिश कर रहे हैं पर निर्भर करता है, तो आप शायद निम्न तरीकों में से एक का प्रयोग करेंगे:

    अपने एक बच्चे की प्रक्रिया में पाश और अपने मुख्य अनुप्रयोग में परिणाम मिलता है "के लिए" यह खत्म हो गया एक बार एक) डाल
    बी) यदि आप देरी की नौकरियों (ईमेल भेजने के लिए) की तरह कुछ हासिल करने की कोशिश कर रहे हैं तो आपको https://github.com/LearnBoost/kue
    सी) मुख्य ऐप और "भारी उठाने के बीच संवाद करने के लिए रेडिस का उपयोग करके अपने स्वयं के क्यू-जैसे प्रोग्राम बनाएं "ऐप।

इन दृष्टिकोणों के लिए आप कई प्रक्रियाओं (समरूपता के लिए) का भी उपयोग कर सकते हैं।

अब एक नमूना कोड के लिए समय (यह सही नहीं हो सकता है, इसलिए यदि आप कोई बेहतर सुझाव है मुझे सही करें):

var forIn, obj; 

// the "for in" loop 
forIn = function(obj, callback){ 
    var keys = Object.keys(obj); 
    (function iterate(keys) { 
    process.nextTick(function() { 
     callback(keys[0], obj[keys[0]]); 
     return ((keys = keys.slice(1)).length && iterate(keys)); 
    }); 
    })(keys); 
}; 

// example usage of forIn 
// console.log the key-val pair in the callback 
function start_processing_the_big_object(my_object) { 
    forIn(my_object, function (key, val) { console.log("key: %s; val: %s;", key, val); }); 
} 

// Let's simulate a big object here 
// and call the function above once the object is created 
obj = {}; 
(function test(obj, i) { 
    obj[i--] = "blah_blah_" + i; 
    if (!i) { start_processing_the_big_object(obj); } 
    return (i && process.nextTick(function() { test(obj, i); })); 
})(obj, 30000); 
+1

मैं चल रहे सभी सरणी स्लाइसिंग के बारे में चिंतित हूं। क्या आपने इसे बेंचमार्क किया था? –

+0

इसे बेंचमार्क नहीं किया था, लेकिन आप निश्चित रूप से स्लाइसिंग के आसपास जा सकते हैं और इसके बजाय एक अलग तकनीक का उपयोग कर सकते हैं (एक ही विचार रखते हुए)। – alessioalex

1

बजाय:

for (var i=0; i<len; i++) { 
    doSomething(i); 
    } 

कुछ इस तरह करते हैं :

var i = 0, limit; 
while (i < len) { 
    limit = (i+100); 
    if (limit > len) 
    limit = len; 
    process.nextTick(function(){ 
    for (; i<limit; i++) { 
     doSomething(i); 
    } 
    }); 
    } 
} 

इस लूप के 100 पुनरावृत्तियों चलेंगे, तो नियंत्रण प्रणाली के लिए एक पल के लिए लौटने के लिए, वें जहां तक ​​यह बंद हो गया, तब तक इसे छोड़ दिया।

संपादित करें: यहाँ यह अपने विशेष मामले के लिए अनुकूलित है (और पुनरावृत्तियों की संख्या के साथ यह एक समय एक तर्क के रूप में पारित में प्रदर्शन):

var forin = function(obj, callback, numPerChunk){ 
    var keys = Object.keys(obj); 
    var len = keys.length; 
    var i = 0, limit; 
    while (i < len) { 
    limit = i + numPerChunk; 
    if (limit > len) 
     limit = len; 
    process.nextTick(function(){ 
     for (; i<limit; i++) { 
      callback(keys[i], obj[keys[i]], obj); 
     } 
     }); 
    } 
} 
+0

क्या आपने वास्तव में इसका परीक्षण किया था? सभी काम पहले 'अगले टिक' में किए जाएंगे, इस प्रकार पुनरावृत्तियों की संख्या के बावजूद बिल्कुल एक बार उपज होगा। –