2012-03-17 15 views
25

में इनलाइन RegExp प्रदर्शन गतिशील मुझे लगता है कि प्रदर्शन परीक्षण पर ठोकर खाई कह रही है कि जावास्क्रिप्ट में regexps जरूरी धीमी गति से नहीं कर रहे हैं,: http://jsperf.com/regexp-indexof-perfबनाम जावास्क्रिप्ट

एक बात मैं हालांकि नहीं मिला है: दो मामलों कुछ है कि मैं करने के लिए विश्वास शामिल ठीक वही होना:

RegExp('(?:^|)foo(?: |$)').test(node.className); 

और

/(?:^|)foo(?: |$)/.test(node.className); 

मेरे मन में, उन दो पंक्तियों थे वास्तव में वही है, दूसरा एक RegExp ऑब्जेक्ट बनाने के लिए किसी प्रकार का शॉर्टेंड है। फिर भी, यह पहले से कहीं अधिक है।

उन मामलों को "गतिशील regexp" और "इनलाइन regexp" कहा जाता है।

क्या कोई इन दोनों के बीच अंतर (और प्रदर्शन अंतर) को समझने में मेरी सहायता कर सकता है?

+1

यह अच्छा है कि "इनलाइन" संस्करण तेज़ है, क्योंकि यह स्पष्ट कन्स्ट्रक्टर का उपयोग करने से बहुत कम बदसूरत है। – Pointy

+0

एक के लिए, आपने 'RegExp' को अधिलेखित किया हो सकता है, इसलिए इसे ए) को सीधे मूल्यांकन करने के बजाय फ़ंक्शन को देखना होगा, और बी) दूसरे को पार्स टाइम पर मूल्यांकन किया जा सकता है जबकि पहला ऐसा नहीं कर सकता क्योंकि 'RegExp' को कॉल करना हो सकता है यदि आपने इसे अधिलेखित किया है तो साइड इफेक्ट्स। – pimvdb

उत्तर

8

प्रदर्शन में अंतर सिंटैक्स से संबंधित नहीं है।

inlineRegExp और storedRegExp के लिए आप कोड देख रहे है कि एक बार जब स्रोत कोड पाठ पार्स किया गया है, जबकि dynamicRegExp के लिए नियमित अभिव्यक्ति विधि से प्रत्येक मंगलाचरण के लिए बनाया जाता आरंभ नहीं हो जाता। ध्यान दें कि actual tests कई बार r = dynamicRegExp(element) जैसी चीजें चलाते हैं, जबकि तैयारी कोड केवल एक बार चलाया जाता है।

निम्नलिखित एक ही परिणाम के बारे में आप देता है, according to another jsPerf:

var reContains = /(?:^|)foo(?: |$)/; 

... और

var reContains = RegExp('(?:^|)foo(?: |$)'); 

... जब दोनों

function storedRegExp(node) { 
    return reContains.test(node.className); 
} 

ज़रूर साथ उपयोग किया जाता है, RegExp('(?:^|)foo(?: |$)') का स्रोत कोड पहले String में पार्स किया जा सकता है, एक nd फिर RegExp में, लेकिन मुझे संदेह है कि स्वयं ही धीमा हो जाएगा। हालांकि, निम्नलिखित प्रत्येक विधि कॉल के लिए बार-बार एक नया RegExp(..)पैदा करेगा:

function dynamicRegExp(node) { 
    return RegExp('(?:^|)foo(?: |$)').test(node.className); 
} 

मूल परीक्षण में आप केवल एक बार प्रत्येक विधि कॉल चाहते हैं, तो इनलाइन संस्करण नहीं एक whopping 2 होगा बार तेजी से।

(मैं और अधिक आश्चर्य inlineRegExp और storedRegExp अलग परिणाम है कि कर रहा हूँ।)

+1

यह वास्तव में बहुत समझ में आता है, धन्यवाद। हो सकता है कि आप [your jsperf] (http://jsperf.com/regexp-indexof-perf/24) को हाइलाइट करना चाहें क्योंकि इससे मुझे यह समझने में सहायता मिली कि प्रदर्शन में अंतर कहां से आता है ('dynamicStoredRegExp' और' dynamicRegExp' के बीच)। और आपके आखिरी वक्तव्य के बारे में, यह इतना अंतर नहीं है, मैं इसे खारिज कर दूंगा। – Pioul

+0

इसके लिए 'inlineRegExp' और' storeRegExp' के बीच का अंतर: पहला [नवीनतम सफारी 6.0 में तेज़ आधा है] (http://jsperf.com/regexp-indexof-perf/24) ...‽ – Arjan

+1

यह नहीं देखा कि, सफारी 6.0 पर दोनों 'संग्रहित रेगएक्सपी' और 'डायनामिकस्टोर रेगएक्सपी' 'इनलाइन रेगएक्सपी' जितनी तेजी से दोगुनी हैं, जब अन्य ब्राउज़रों पर यह काफी समान होता है। अब मैं भी उत्सुक हूं कि सफारी के साथ क्या हो रहा है ... – Pioul

6

दूसरे मामले में, नियमित अभिव्यक्ति वस्तु भाषा के विश्लेषण के दौरान बनाई गई है, और पहले मामले में, RegExp क्लास कन्स्ट्रक्टर को मनमाने ढंग से स्ट्रिंग को पार्स करना पड़ता है।

+0

आप जो कह रहे हैं वह यह है कि पहले मामले में, इंजन द्वारा "समझा" जाने से पहले regexp प्रकार "स्ट्रिंग" स्थिति के माध्यम से जाता है? – Pioul

+0

हाँ, यह सही है। – dldnh

+0

ओह, इससे भी बेहतर, मुझे बताएं कि क्या मैं सही हूं: रेगेक्स डिलीमीटर के रूप में काम को धीमा कर देता है, ताकि एक स्लैश एक रेगेक्स का अर्थ हो जितना उद्धरण एक स्ट्रिंग का तात्पर्य है? – Pioul

13

आजकल, यहां दिए गए उत्तर पूरी तरह से पूरा/सही नहीं हैं।

ES5 से शुरू, शाब्दिक वाक्य रचना व्यवहार RegExp() वाक्य रचना के बारे में वस्तु रचना के रूप में एक ही है: उन दोनों को एक नया RegExp ऑब्जेक्ट हर बार कोड पथ एक अभिव्यक्ति है जिसमें वे भाग ले रहे हैं हिट बनाता है।

इसलिए, उन दोनों के बीच फर्क सिर्फ इतना है अब कितनी बार है कि regexp संकलित किया गया है है:

    शाब्दिक वाक्य रचना के साथ
  • - एक बार प्रारंभिक कोड पार्सिंग के दौरान और संकलन
  • RegExp() वाक्य रचना के साथ - हर बार नई वस्तु

देखें, उदाहरण के लिए, Stoyan Stefanov's JavaScript Patterns पुस्तक:

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

function getRE() { 
    var re = /[a-z]/; 
    re.foo = "bar"; 
    return re; 
} 

var reg = getRE(), 
    re2 = getRE(); 

console.log(reg === re2); // true 
reg.foo = "baz"; 
console.log(re2.foo); // "baz" 

यह व्यवहार ES5 में बदल गया है और शाब्दिक भी नई वस्तुओं पैदा करता है। व्यवहार को कई ब्राउज़र वातावरण में भी ठीक किया गया है, इसलिए इस पर भरोसा नहीं किया जाना चाहिए।

आप सभी आधुनिक ब्राउज़रों या NodeJS में इस नमूने चलाते हैं, तो आप के बजाय निम्नलिखित मिलती है:

false 
bar 

कि मतलब ई बहुत बार जब आप getRE() समारोह कॉल कर रहे हैं, एक नया RegExp वस्तु शाब्दिक वाक्यविन्यास दृष्टिकोण के साथ भी बनाया गया है।

नहीं ऊपर केवल बताता है कि क्यों आप अपरिवर्तनीय regexps के लिए RegExp() (यह बहुत अच्छी तरह से प्रदर्शन मुद्दा जाना जाता है आज) उपयोग नहीं करना चाहिए, लेकिन यह भी बताते हैं:

(मैं और अधिक आश्चर्य inlineRegExp और storedRegExp है कि कर रहा हूँ विभिन्न परिणाम)

storedRegExp के बारे में 5 है -। inlineRegExp से ब्राउज़रों में 20% प्रतिशत तेजी से बनाने (और कचरा एकत्र करने) एक नई RegExp वस्तु पूर्व संध्या का कोई भूमि के ऊपर है, क्योंकि आरई समय

निष्कर्ष:
हमेशा शाब्दिक वाक्य रचना और यह कैश के साथ अपने अपरिवर्तनीय regexps बनाने इसे फिर से इस्तेमाल किया जा रहा है या नहीं।दूसरे शब्दों में, ईएस 5 के नीचे envs में व्यवहार में उस अंतर पर भरोसा न करें, और उपरोक्त envs में उचित कैशिंग जारी रखें।

शाब्दिक वाक्यविन्यास क्यों? यह कुछ निर्माता वाक्य रचना की तुलना में लाभ होता है:

  1. यह कम है और वर्ग की तरह कंस्ट्रक्टर्स के संदर्भ में सोचने के लिए आप के लिए मजबूर नहीं है।
  2. RegExp() कन्स्ट्रक्टर का उपयोग करते समय, आपको उद्धरण और डबल-एस्केप बैकस्लाश से बचने की भी आवश्यकता है। यह नियमित अभिव्यक्ति बनाता है जो उनकी प्रकृति को और भी कठिन बनाने के लिए कठिन और समझना कठिन होता है।

(एक ही Stoyan Stefanov's JavaScript Patterns किताब से नि: शुल्क प्रशस्ति पत्र)।
इसलिए, शाब्दिक वाक्यविन्यास के साथ रहना हमेशा अच्छा विचार है, जब तक कि आपका regexp संकलन समय पर ज्ञात न हो।

+0

इस अच्छे अपडेट के लिए धन्यवाद! मुझे निष्कर्ष भी पसंद है, हालांकि मैं यह कहने का लुत्फ उठाऊंगा कि "जो भी आप रेगेक्स, शाब्दिक या कन्स्ट्रक्टर बनाने के लिए पसंद करते हैं, उसके साथ जाएं, और इसे फिर से उपयोग करने के लिए कैश करें"। दूसरे शब्दों में, ईएस 5 के नीचे envs में व्यवहार में उस अंतर पर भरोसा न करें, और उपरोक्त envs में उचित कैशिंग जारी रखें :) – Pioul

+1

@Pioul, प्रतिक्रिया के लिए धन्यवाद! मैंने अपना जवाब अपडेट कर लिया है और जैसा कि आपने कन्स्ट्रक्टर पैटर्न के हिस्से को छोड़कर सुझाव दिया है। मेरा जवाब देखें :) –

+0

आमीन! : डी – Pioul

संबंधित मुद्दे