2010-08-28 11 views
6

मैं जावास्क्रिप्ट प्रदर्शन का शोध कर रहा हूं। मैंने सीखा है कि एक से अधिक बार पहुंचने पर, चीजों को गति देने के लिए बंद करने के चर और वर्ग के सदस्यों को स्थानीय दायरे में कॉपी करना सबसे अच्छा होता है। उदाहरण के लिए:जब ठीक-ठीक प्रदर्शन होता है, तो जावास्क्रिप्ट विधियों को कई बार कॉल करने का सबसे अच्छा तरीका क्या है?

var i = 100; 
var doSomething = function() { 
    var localI = i; 
    // do something with localI a bunch of times 

    var obj = { 
     a: 100 
    }; 
    var objA = obj.a; 
    // do something with objA a bunch of times 
}; 

मैं इसे समझता हूं; यह नाम से मूल्य को देखने वाले दुभाषिया के लिए एक शॉर्टकट जोड़ता है। तरीकों से निपटने के दौरान यह अवधारणा बहुत अस्पष्ट हो जाती है। सबसे पहले, मैंने सोचा कि यह वही काम करेगा। उदाहरण के लिए:

var obj = { 
    fn: function() { 
     // Do something 
     return this.value; 
    }, 
    value: 100 
}; 
var objFn = obj.fn 
objFn(); 
// call objFn a bunch of times 

जैसा कि यह है, यह बिल्कुल काम नहीं करेगा। इस तरह की विधि तक पहुंचने से इसे अपने दायरे से हटा दिया जाता है। जब यह लाइन को पहुंचाता है। औसत, यह विंडो ऑब्जेक्ट को संदर्भित करता है और यह .value शायद अपरिभाषित होगा। ObjFn को सीधे कॉल करने और गुंजाइश खोने के बजाय, मैं obpFn.call (obj) के साथ अपने दायरे को वापस कर सकता हूं लेकिन क्या यह मूल obj.fn() के बाद कोई बेहतर या बदतर करता है?

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

एक वस्तु इस पर कई सरल तरीकों से बनाई गई है। यह निर्धारित करने के लिए अतिरिक्त विधियां हैं कि क्या एक विशिष्ट विधि का पता लगाने के लिए दुभाषिया को अधिक कठिन परिश्रम करना पड़ता है।

टेस्ट 1 बस यह कहता है। ए();
टेस्ट 2 एक स्थानीय चर बनाता है = this.a फिर a.call (यह) को कॉल करता है;
टेस्ट 3 स्कोप को संरक्षित करने के लिए वाईयूआई के बाइंड फ़ंक्शन का उपयोग करके स्थानीय चर बनाता है। मैंने इस पर टिप्पणी की। यूयूआई द्वारा बनाई गई अतिरिक्त फ़ंक्शन कॉल इस तरह धीमी गति से बनाते हैं।

टेस्ट 4, 5, और 6 एक के बजाय जेड का उपयोग करने के अलावा 1, 2, 3 की प्रतियां हैं।

वाईयूआई के बाद के फ़ंक्शन का उपयोग रनवे स्क्रिप्ट त्रुटियों को रोकने के लिए किया जाता है। समय वास्तविक परीक्षण विधियों में किया जाता है ताकि सेटटाइमआउट परिणामों को प्रभावित न करे। प्रत्येक समारोह को कुल 10000000 बार कहा जाता है। (यदि आप परीक्षण चलाने के लिए चाहते हैं तो आसानी से कॉन्फ़िगर करने योग्य।)

मेरा पूरा एक्सएचटीएमएल दस्तावेज़ मैं परीक्षण करने के लिए उपयोग करता हूं।

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xml:lang="en" dir="ltr"> 
    <head> 
     <script type="text/javascript" src="http://yui.yahooapis.com/combo?3.1.2/build/yui/yui-min.js"></script> 
     <script> 
      YUI().use('node', function (Y) { 
       var o = { 
        value: '', 
        a: function() { 
         this.value += 'a'; 
        }, 
        b: function() { 
         this.value += 'b'; 
        }, 
        c: function() { 
         this.value += 'c'; 
        }, 
        d: function() { 
         this.value += 'd'; 
        }, 
        e: function() { 
         this.value += 'e'; 
        }, 
        f: function() { 
         this.value += 'f'; 
        }, 
        g: function() { 
         this.value += 'g'; 
        }, 
        h: function() { 
         this.value += 'h'; 
        }, 
        i: function() { 
         this.value += 'i'; 
        }, 
        j: function() { 
         this.value += 'j'; 
        }, 
        k: function() { 
         this.value += 'k'; 
        }, 
        l: function() { 
         this.value += 'l'; 
        }, 
        m: function() { 
         this.value += 'm'; 
        }, 
        n: function() { 
         this.value += 'n'; 
        }, 
        o: function() { 
         this.value += 'o'; 
        }, 
        p: function() { 
         this.value += 'p'; 
        }, 
        q: function() { 
         this.value += 'q'; 
        }, 
        r: function() { 
         this.value += 'r'; 
        }, 
        s: function() { 
         this.value += 's'; 
        }, 
        t: function() { 
         this.value += 't'; 
        }, 
        u: function() { 
         this.value += 'u'; 
        }, 
        v: function() { 
         this.value += 'v'; 
        }, 
        w: function() { 
         this.value += 'w'; 
        }, 
        x: function() { 
         this.value += 'x'; 
        }, 
        y: function() { 
         this.value += 'y'; 
        }, 
        z: function() { 
         this.value += 'z'; 
        }, 
        reset: function() { 
         this.value = ''; 
        }, 
        test1: function (length) { 
         var time = new Date().getTime(); 

         while ((length -= 1)) { 
          this.a(); 
         } 
         return new Date().getTime() - time; 
        }, 
        test2: function (length) { 
         var a = this.a, 
         time = new Date().getTime(); 

         while ((length -= 1)) { 
          a.call(this); 
         } 
         return new Date().getTime() - time; 
        }, 
        test3: function (length) { 
         var a = Y.bind(this.a, this), 
         time = new Date().getTime(); 

         while ((length -= 1)) { 
          a(); 
         } 
         return new Date().getTime() - time; 
        }, 
        test4: function (length) { 
         var time = new Date().getTime(); 

         while ((length -= 1)) { 
          this.z(); 
         } 
         return new Date().getTime() - time; 
        }, 
        test5: function (length) { 
         var z = this.z, 
         time = new Date().getTime(); 

         while ((length -= 1)) { 
          z.call(this); 
         } 
         return new Date().getTime() - time; 
        }, 
        test6: function (length) { 
         var z = Y.bind(this.z, this), 
         time = new Date().getTime(); 

         while ((length -= 1)) { 
          z(); 
         } 
         return new Date().getTime() - time; 
        } 
       }, 
       iterations = 100, iteration = iterations, length = 100000, 
       t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, body = Y.one('body'); 

       body.set('innerHTML', '<span>Running ' + iterations + ' Iterations&hellip;</span>'); 
       while ((iteration -= 1)) { 
        Y.later(1, null, function (iteration) { 
         Y.later(1, null, function() { 
          o.reset(); 
          t1 += o.test1(length); 
         }); 
         Y.later(1, null, function() { 
          o.reset(); 
          t2 += o.test2(length); 
         }); 
         /*Y.later(1, null, function() { 
          o.reset(); 
          t3 += o.test3(length); 
         });*/ 
         Y.later(1, null, function() { 
          o.reset(); 
          t4 += o.test4(length); 
         }); 
         Y.later(1, null, function() { 
          o.reset(); 
          t5 += o.test5(length); 
         }); 
         /*Y.later(1, null, function() { 
          o.reset(); 
          t6 += o.test6(length); 
         });*/ 
         if (iteration === 1) { 
          Y.later(10, null, function() { 
           t1 /= iterations; 
           t2 /= iterations; 
           //t3 /= iterations; 
           t4 /= iterations; 
           t5 /= iterations; 
           //t6 /= iterations; 

           //body.set('innerHTML', '<dl><dt>Test 1: this.a();</dt><dd>' + t1 + '</dd><dt>Test 2: a.call(this);</dt><dd>' + t2 + '</dd><dt>Test 3: a();</dt><dd>' + t3 + '</dd><dt>Test 4: this.z();</dt><dd>' + t4 + '</dd><dt>Test 5: z.call(this);</dt><dd>' + t5 + '</dd><dt>Test 6: z();</dt><dd>' + t6 + '</dd></dl>'); 
           body.set('innerHTML', '<dl><dt>Test 1: this.a();</dt><dd>' + t1 + '</dd><dt>Test 2: a.call(this);</dt><dd>' + t2 + '</dd><dt>Test 4: this.z();</dt><dd>' + t4 + '</dd><dt>Test 5: z.call(this);</dt><dd>' + t5 + '</dd></dl>'); 
          }); 
         } 
        }, iteration); 
       } 
      }); 
     </script> 
    </head> 
    <body> 
    </body> 
</html> 

मैंने इसे तीन अलग-अलग ब्राउज़रों में विंडोज 7 का उपयोग करके चलाया है। ये परिणाम मिलीसेकंड में हैं।

फ़ायरफ़ॉक्स 3.6.8

Test 1: this.a(); 
    9.23 
Test 2: a.call(this); 
    9.67 
Test 4: this.z(); 
    9.2 
Test 5: z.call(this); 
    9.61 

क्रोम 7.0.503.0

Test 1: this.a(); 
    5.25 
Test 2: a.call(this); 
    4.66 
Test 4: this.z(); 
    3.71 
Test 5: z.call(this); 
    4.15 

इंटरनेट एक्सप्लोरर 8

Test 1: this.a(); 
    168.2 
Test 2: a.call(this); 
    197.94 
Test 4: this.z(); 
    169.6 
Test 5: z.call(this); 
    199.02 

फ़ायरफ़ॉक्स और इंटरनेट एक्सप्लोरर का उत्पादन मैं कैसे उम्मीद के बारे में परिणाम है। टेस्ट 1 और टेस्ट 4 अपेक्षाकृत करीब हैं, टेस्ट 2 और टेस्ट 5 अपेक्षाकृत करीब हैं, और टेस्ट 2 और टेस्ट 5 टेस्ट 1 और टेस्ट 4 से अधिक समय लेते हैं क्योंकि प्रक्रिया के लिए एक अतिरिक्त फंक्शन कॉल है।

क्रोम मुझे बिल्कुल समझ में नहीं आता है, लेकिन यह बहुत तेज है, शायद उप-मिलीसेकंद प्रदर्शन का tweaking अनावश्यक है।

क्या किसी के पास परिणामों का अच्छा स्पष्टीकरण है? जावास्क्रिप्ट विधियों को कई बार कॉल करने का सबसे अच्छा तरीका क्या है?

+2

आप अपने प्रश्न में इस लिंक जोड़ सकते हैं, ताकि अन्य उपयोगकर्ता परीक्षण के लिए खुद को चला सकता हूँ? - http://jsfiddle.net/Lbbx5/ – Anurag

+1

संबंधित पढ़ा गया: ["इस" के बिना जावास्क्रिप्ट विजेट] (http://michaux.ca/articles/javascript-widgets-without-this) –

+1

एफवाईआई, क्रोमियम (लिनक्स) का उपयोग करके मेरे (अपेक्षाकृत धीमी) प्रणाली पर, कुछ परीक्षणों के बाद ऐसा लगता है कि परिणाम फ़ायरफ़ॉक्स (केवल तेज़) के समान होते हैं: संयोजन 1/4 और 2/5 कम या कम होते हैं और 2 और 5 धीमे होते हैं 1 और 4. –

उत्तर

1

ठीक है, जब तक आपकी वेबसाइट के आगंतुकों के रूप में IE8 उपयोगकर्ता हैं, यह काफी अप्रासंगिक है। 1 या 3 का प्रयोग करें (उपयोगकर्ता एक अंतर नहीं देखेंगे)।

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

+0

किसी भी वास्तविक एप्लिकेशन में जो लाखों बार फिर से शुरू करना है, यह शायद मूल्य + = 'ए' की तुलना में अधिक जटिल कार्यों को बुलाएगा और यह शायद प्रति पुनरावृत्ति एक से अधिक फ़ंक्शन को कॉल करेगा। इस परीक्षण में इंटरनेट एक्सप्लोरर पर लगभग तीस मिलीसेकंड का अनुकूलन अप्रासंगिक हो सकता है लेकिन जब एप्लिकेशन को वास्तव में कुछ करने के लिए अधिक समय लगता है और तीस मिलीसेकंड को दो दर्जन फ़ंक्शन कॉल से गुणा किया जाता है, तो यह बहुत ही ध्यान देने योग्य अंतराल को जोड़ना शुरू कर देता है। – Killthesand

2

बस theorizing है, तो एक अलग नज़रिए के साथ इस ले ...

Chrome की JavaScript इंजन, वी 8, हिडन वर्ग कहा जाता है एक अनुकूलन तकनीक का उपयोग करता। मूल रूप से यह स्थैतिक ऑब्जेक्ट्स बनाता है जो गतिशील जावास्क्रिप्ट ऑब्जेक्ट्स छाया करते हैं, जहां प्रत्येक प्रॉपर्टी/विधि को एक निश्चित मेमोरी एड्रेस में मैप किया जाता है जिसे एक महंगे टेबल लुकअप ऑपरेशन की आवश्यकता के साथ संदर्भित किया जा सकता है। प्रत्येक बार जावास्क्रिप्ट ऑब्जेक्ट में एक संपत्ति को जोड़ा/हटा दिया जाता है, एक नई छिपी हुई कक्षा बनाई जाती है।

क्रोम के साथ आपके परीक्षण के परिणामों के लिए मेरा सिद्धांत, यह है कि एक मुक्त स्थानीय चर में फ़ंक्शन का संदर्भ छुपा वर्ग संबंध तोड़ता है। स्थानीय चरों को संदर्भित करते समय शायद एक टेबल लुकअप की आवश्यकता नहीं होती है, तो 'यह' चर फिर से असाइन करने में एक अतिरिक्त कदम अब किया जाना चाहिए। एक छिपी हुई कक्षा पर एक विधि के लिए, 'यह' एक निश्चित मान है, इसलिए इसे इस चरण के बिना बुलाया जा सकता है।

फिर से सिर्फ थियोरिज़िंग। क्रोम में स्थानीय परिवर्तनीय संदर्भ बनाम ऑब्जेक्ट। मेम्बर संदर्भों के बीच अंतर को बेंचमार्क करने के लिए यह परीक्षण के लायक हो सकता है, यह देखने के लिए कि बाद के लिए प्रदर्शन करने के लिए हिट छुपा वर्गों की वजह से अन्य ब्राउज़रों की तुलना में कम है।

+0

वी 8 इंजन में छिपा वर्गों की अवधारणा यह भी अजनबी बनाता है। यह .a() को कॉल क्यों कर रहा है यह .z() को कॉल करने से कहीं अधिक महंगा है? A.call (यह) को कॉल करना इस .a() को कॉल करने से कम महंगा है, लेकिन z.call (यह) को कॉल करना इस .z() को कॉल करने से अधिक महंगा है। क्या वे मेमोरी पॉइंटर्स को डिफ्रेंस करने के बजाय सदस्यों के माध्यम से पुन: प्रयास कर रहे हैं? मैं सोच रहा हूं कि ये परिणाम विश्वसनीय हैं या नहीं।हम 3-5 मिलीसेकंड के पैमाने पर हैं; मैं शायद अपने माउस को स्क्रीन के चारों ओर ले जा सकता हूं और इन परिणामों को विकृत कर सकता हूं। मैं क्रोम पर पुनरावृत्तियों की एक बड़ी संख्या का प्रयास करूंगा और देख सकता हूं कि यह कैसे करता है। – Killthesand

+0

मैंने क्रोम पर एक और परीक्षण चलाया है, प्रत्येक 1000 लाख टिप्पणियों के साथ 1000 पुनरावृत्तियों। इसे चलाने में काफी समय लगा लेकिन बहुत अधिक लगातार परिणाम प्रदान किए गए। टेस्ट 1: this.a(); 168.475 टेस्ट 2: a.call (यह); 172.069 टेस्ट 4: this.z(); 168.936 टेस्ट 5: z.call (यह); 173.012 – Killthesand

1

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

Here's an easy way to find out which code is responsible for much time.

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

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