ক্লোজার কম্পাইলার দ্বারা আরোপিত বিধিনিষেধ বোঝা

ক্লোজার কম্পাইলার আশা করে যে তার জাভাস্ক্রিপ্ট ইনপুট কয়েকটি বিধিনিষেধ মেনে চলবে। আপনি কম্পাইলারকে যত উচ্চতর অপ্টিমাইজেশান করতে বলবেন, কম্পাইলার ইনপুট জাভাস্ক্রিপ্টে তত বেশি সীমাবদ্ধতা রাখে।

এই নথিটি অপ্টিমাইজেশানের প্রতিটি স্তরের জন্য প্রধান সীমাবদ্ধতাগুলি বর্ণনা করে৷ কম্পাইলার দ্বারা তৈরি অতিরিক্ত অনুমানের জন্য এই উইকি পৃষ্ঠাটিও দেখুন।

সমস্ত অপ্টিমাইজেশান স্তরের জন্য সীমাবদ্ধতা

কম্পাইলার সমস্ত জাভাস্ক্রিপ্টে নিম্নলিখিত দুটি সীমাবদ্ধতা রাখে যা এটি প্রক্রিয়া করে, সমস্ত অপ্টিমাইজেশান স্তরের জন্য:

  • কম্পাইলার শুধুমাত্র ECMAScript চিনতে পারে।

    ECMAScript 5 হল জাভাস্ক্রিপ্টের সংস্করণ যা প্রায় সর্বত্র সমর্থিত। তবে কম্পাইলারটি ECMAScript 6-এর অনেক বৈশিষ্ট্য সমর্থন করে। কম্পাইলার শুধুমাত্র অফিসিয়াল ভাষার বৈশিষ্ট্য সমর্থন করে।

    ব্রাউজার-নির্দিষ্ট বৈশিষ্ট্য যা উপযুক্ত ECMAScript ভাষার স্পেসিফিকেশনের সাথে সঙ্গতিপূর্ণ, কম্পাইলারের সাথে ভাল কাজ করবে। উদাহরণস্বরূপ, ActiveX অবজেক্টগুলি আইনি জাভাস্ক্রিপ্ট সিনট্যাক্স দিয়ে তৈরি করা হয়, তাই কোড যা ActiveX অবজেক্ট তৈরি করে কম্পাইলারের সাথে কাজ করে।

    কম্পাইলার রক্ষণাবেক্ষণকারীরা সক্রিয়ভাবে নতুন ভাষা সংস্করণ এবং তাদের বৈশিষ্ট্য সমর্থন করার জন্য কাজ করে। প্রকল্পগুলি --language_in পতাকা ব্যবহার করে তারা কোন ECMAScript ভাষার সংস্করণ করতে চায় তা নির্দিষ্ট করতে পারে।

  • কম্পাইলার মন্তব্য সংরক্ষণ করে না।

    সমস্ত কম্পাইলার অপ্টিমাইজেশান লেভেল মন্তব্যগুলি সরিয়ে দেয়, তাই বিশেষভাবে ফর্ম্যাট করা মন্তব্যের উপর নির্ভর করে এমন কোড কম্পাইলারের সাথে কাজ করে না।

    উদাহরণস্বরূপ, যেহেতু কম্পাইলার মন্তব্যগুলি সংরক্ষণ করে না, আপনি সরাসরি JScript এর "শর্তাধীন মন্তব্য" ব্যবহার করতে পারবেন না। যাইহোক, আপনি eval() এক্সপ্রেশনে শর্তসাপেক্ষ মন্তব্যগুলি মোড়ানোর মাধ্যমে এই সীমাবদ্ধতার চারপাশে কাজ করতে পারেন। কম্পাইলার একটি ত্রুটি তৈরি না করে নিম্নলিখিত কোড প্রক্রিয়া করতে পারে:

     x = eval("/*@cc_on 2+@*/ 0");
    

    দ্রষ্টব্য: আপনি @preserve টীকা ব্যবহার করে কম্পাইলার আউটপুটের শীর্ষে ওপেন সোর্স লাইসেন্স এবং অন্যান্য গুরুত্বপূর্ণ পাঠ্য অন্তর্ভুক্ত করতে পারেন।

SIMPLE_OPTIMIZATIONS এর জন্য সীমাবদ্ধতা

সরল অপ্টিমাইজেশান স্তর ফাংশন পরামিতি, স্থানীয় ভেরিয়েবল, এবং স্থানীয়ভাবে সংজ্ঞায়িত ফাংশন কোড আকার কমাতে পুনরায় নামকরণ করে। যাইহোক, কিছু জাভাস্ক্রিপ্ট কনস্ট্রাক্ট এই পুনঃনামকরণ প্রক্রিয়াটি ভঙ্গ করতে পারে।

SIMPLE_OPTIMIZATIONS ব্যবহার করার সময় নিম্নলিখিত গঠন এবং অনুশীলনগুলি এড়িয়ে চলুন:

  • with :

    আপনি যখন কম্পাইলারের with ব্যবহার করেন তখন একটি স্থানীয় ভেরিয়েবল এবং একই নামের একটি বস্তুর বৈশিষ্ট্যের মধ্যে পার্থক্য করতে পারে না এবং তাই এটি নামের সমস্ত উদাহরণের নাম পরিবর্তন করে।

    উপরন্তু, বিবৃতি with মানুষের জন্য আপনার কোড পড়া কঠিন করে তোলে। with স্টেটমেন্ট নামের রেজোলিউশনের স্বাভাবিক নিয়মগুলিকে পরিবর্তন করে, এবং কোডটি লিখেছিলেন এমন প্রোগ্রামারের জন্যও একটি নাম কী বোঝায় তা সনাক্ত করা কঠিন করে তুলতে পারে।

  • eval() :

    কম্পাইলার eval() এর স্ট্রিং আর্গুমেন্ট পার্স করে না, এবং তাই এই আর্গুমেন্টের মধ্যে কোনো চিহ্নের নাম পরিবর্তন করবে না।

  • ফাংশন বা পরামিতি নামের স্ট্রিং উপস্থাপনা:

    কম্পাইলার ফাংশন এবং ফাংশন পরামিতিগুলির নাম পরিবর্তন করে কিন্তু আপনার কোডের কোনও স্ট্রিং পরিবর্তন করে না যা নাম অনুসারে ফাংশন বা পরামিতিগুলিকে উল্লেখ করে। এইভাবে আপনার কোডে স্ট্রিং হিসাবে ফাংশন বা প্যারামিটারের নামগুলি উপস্থাপন করা এড়ানো উচিত। উদাহরণস্বরূপ, প্রোটোটাইপ লাইব্রেরি ফাংশন argumentNames() একটি ফাংশনের প্যারামিটারের নাম পুনরুদ্ধার করতে Function.toString() ) ব্যবহার করে। কিন্তু যখন argumentNames() আপনাকে আপনার কোডে আর্গুমেন্টের নাম ব্যবহার করতে প্রলুব্ধ করতে পারে, সরল মোড সংকলন এই ধরনের রেফারেন্স ভেঙে দেয়।

ADVANCED_OPTIMIZATIONS এর জন্য বিধিনিষেধ

ADVANCED_OPTIMIZATIONS সংকলন স্তরটি SIMPLE_OPTIMIZATIONS এর মতো একই রূপান্তর সম্পাদন করে এবং এছাড়াও বৈশিষ্ট্য, ভেরিয়েবল এবং ফাংশনগুলির বিশ্বব্যাপী পুনঃনামকরণ, ডেড কোড নির্মূল এবং সম্পত্তি সমতলকরণ যোগ করে৷ এই নতুন পাসগুলি ইনপুট জাভাস্ক্রিপ্টের উপর অতিরিক্ত সীমাবদ্ধতা রাখে। সাধারণভাবে, জাভাস্ক্রিপ্টের গতিশীল বৈশিষ্ট্যগুলি ব্যবহার করা আপনার কোডে সঠিক স্ট্যাটিক বিশ্লেষণ প্রতিরোধ করবে।

গ্লোবাল ভেরিয়েবল, ফাংশন এবং প্রোপার্টি রিনেমিং এর প্রভাব:

ADVANCED_OPTIMIZATIONS এর বিশ্বব্যাপী পুনঃনামকরণ নিম্নলিখিত অনুশীলনগুলিকে বিপজ্জনক করে তোলে:

  • অঘোষিত বাহ্যিক রেফারেন্স:

    বিশ্বব্যাপী ভেরিয়েবল, ফাংশন এবং বৈশিষ্ট্যগুলি সঠিকভাবে পুনঃনামকরণ করার জন্য, কম্পাইলারকে অবশ্যই সেই গ্লোবালগুলির সমস্ত রেফারেন্স সম্পর্কে জানতে হবে। সংকলিত কোডের বাইরে সংজ্ঞায়িত চিহ্ন সম্পর্কে আপনাকে অবশ্যই কম্পাইলারকে বলতে হবে। অ্যাডভান্সড কম্পাইলেশন এবং এক্সটার্নস বর্ণনা করে কিভাবে বাহ্যিক চিহ্ন ঘোষণা করা যায়।

  • বাহ্যিক কোডে অরপ্তানিকৃত অভ্যন্তরীণ নাম ব্যবহার করা:

    কম্পাইল করা কোড অবশ্যই যেকোন চিহ্ন রপ্তানি করতে হবে যা আনকম্পাইল করা কোড নির্দেশ করে। অ্যাডভান্সড কম্পাইলেশন এবং এক্সটার্নস বর্ণনা করে কিভাবে প্রতীক রপ্তানি করা যায়।

  • বস্তুর বৈশিষ্ট্য উল্লেখ করতে স্ট্রিং নাম ব্যবহার করে:

    কম্পাইলার উন্নত মোডে বৈশিষ্ট্যের নাম পরিবর্তন করে, কিন্তু এটি কখনই স্ট্রিংগুলির নাম পরিবর্তন করে না।

      var x = { renamed_property: 1 };
      var y = x.renamed_property; // This is OK.
    
      // 'renamed_property' below doesn't exist on x after renaming, so the
      //  following evaluates to false.
      if ( 'renamed_property' in x ) {}; // BAD
    
      // The following also fails:
      x['renamed_property']; // BAD
    

    আপনি যদি উদ্ধৃত স্ট্রিং সহ একটি সম্পত্তি উল্লেখ করতে চান তবে সর্বদা একটি উদ্ধৃত স্ট্রিং ব্যবহার করুন:

      var x = { 'unrenamed_property': 1 };
      x['unrenamed_property'];  // This is OK.
      if ( 'unrenamed_property' in x ) {};   // This is OK
    
  • বৈশ্বিক বস্তুর বৈশিষ্ট্য হিসাবে ভেরিয়েবলকে উল্লেখ করা:

    কম্পাইলার স্বতন্ত্রভাবে বৈশিষ্ট্য এবং ভেরিয়েবলের নাম পরিবর্তন করে। উদাহরণস্বরূপ, কম্পাইলার foo এর নিম্নলিখিত দুটি রেফারেন্সকে ভিন্নভাবে ব্যবহার করে, যদিও তারা সমতুল্য:

      var foo = {};
      window.foo; // BAD
    

    এই কোড কম্পাইল হতে পারে:

      var a = {};
      window.b;
    

    আপনি যদি বৈশ্বিক বস্তুর সম্পত্তি হিসাবে একটি পরিবর্তনশীলকে উল্লেখ করতে চান তবে সর্বদা এটিকে এইভাবে উল্লেখ করুন:

    window.foo = {}
    window.foo;
    

Implications of dead code elimination

The ADVANCED_OPTIMIZATIONS compilation level removes code that is never executed. This elimination of dead code makes the following practices dangerous:

  • Calling functions from outside of compiled code:

    When you compile functions without compiling the code that calls those functions, the Compiler assumes that the functions are never called and removes them. To avoid unwanted code removal, either:

    • compile all the JavaScript for your application together, or
    • export compiled functions.

    Advanced Compilation and Externs describes both of these approaches in greater detail.

  • Retrieving functions through iteration over constructor or prototype properties:

    To determine whether a function is dead code, the Compiler has to find all the calls to that function. By iterating over the properties of a constructor or its prototype you can find and call methods, but the Compiler can't identify the specific functions called in this manner.

    For example, the following code causes unintended code removal:

    function Coordinate() {
    }
    Coordinate.prototype.initX = function() {
      this.x = 0;
    }
    Coordinate.prototype.initY = function() {
      this.y = 0;
    }
    var coord = new Coordinate();
    for (method in Coordinate.prototype) {
      Coordinate.prototype[method].call(coord); // BAD
    }
        

    কম্পাইলার বুঝতে পারে না যে initX() এবং initY() লুপের for কল করা হয়েছে, এবং তাই এটি এই উভয় পদ্ধতিকে সরিয়ে দেয়।

    মনে রাখবেন যে আপনি যদি প্যারামিটার হিসাবে একটি ফাংশন পাস করেন, কম্পাইলার সেই প্যারামিটারে কল খুঁজে পেতে পারে । উদাহরণস্বরূপ, কম্পাইলার getHello() ফাংশনটি সরিয়ে দেয় না যখন এটি উন্নত মোডে নিম্নলিখিত কোডটি কম্পাইল করে।

    function alertF(f) {
      alert(f());
    }
    function getHello() {
      return 'hello';
    }
    // The Compiler figures out that this call to alertF also calls getHello().
    alertF(getHello); // This is OK.
        

বস্তুর সম্পত্তি সমতলকরণের প্রভাব

অ্যাডভান্সড মোডে কম্পাইলার নাম সংক্ষিপ্ত করার জন্য প্রস্তুত করার জন্য অবজেক্টের বৈশিষ্ট্যগুলিকে ভেঙে দেয়। উদাহরণস্বরূপ, কম্পাইলার এটি রূপান্তরিত করে:

   var foo = {};
   foo.bar = function (a) { alert(a) };
   foo.bar("hello");

এর মধ্যে:

   var foo$bar = function (a) { alert(a) };
   foo$bar("hello");

এই সম্পত্তি সমতলকরণ পরবর্তী নামকরণ পাসকে আরও দক্ষতার সাথে নাম পরিবর্তন করতে দেয়। কম্পাইলার foo$bar একটি একক অক্ষর দিয়ে প্রতিস্থাপন করতে পারে, উদাহরণস্বরূপ।

কিন্তু সম্পত্তি সমতল করা নিম্নলিখিত অনুশীলনগুলিকে বিপজ্জনক করে তোলে:

  • কনস্ট্রাক্টর এবং প্রোটোটাইপ পদ্ধতির বাইরে this ব্যবহার করে:

    সম্পত্তি সমতলকরণ একটি ফাংশনের মধ্যে this কীওয়ার্ডটির অর্থ পরিবর্তন করতে পারে। উদাহরণ স্বরূপ:

       var foo = {};
       foo.bar = function (a) { this.bad = a; }; // BAD
       foo.bar("hello");
    

    হয়ে যায়:

       var foo$bar = function (a) { this.bad = a; };
       foo$bar("hello");
    

    রূপান্তরের আগে, foo.bar এর মধ্যে this foo কে বোঝায়। রূপান্তরের this , this বিশ্বব্যাপী বোঝায়। এই ধরনের ক্ষেত্রে কম্পাইলার এই সতর্কতা তৈরি করে:

    "WARNING - dangerous use of this in static method foo.bar"

    এতে আপনার রেফারেন্স ভাঙ্গা থেকে সম্পত্তি সমতল হওয়া প্রতিরোধ this , শুধুমাত্র কনস্ট্রাক্টর এবং প্রোটোটাইপ পদ্ধতির মধ্যে এটি ব্যবহার thisthis অর্থ দ্ব্যর্থহীন হয় যখন আপনি একটি new কীওয়ার্ড দিয়ে একটি কনস্ট্রাক্টরকে কল করেন, বা একটি ফাংশনের মধ্যে যা একটি prototype সম্পত্তি।

  • তারা কোন ক্লাসে ডাকা হয়েছে তা না জেনে স্ট্যাটিক পদ্ধতি ব্যবহার করা:

    উদাহরণস্বরূপ, যদি আপনার কাছে থাকে:

    class A { static create() { return new A(); }};
    class B { static create() { return new B(); }};
    let cls = someCondition ? A : B;
    cls.create();
    
    কম্পাইলারটি উভয় create পদ্ধতিকে ভেঙে ফেলবে (ES6 থেকে ES5 তে স্থানান্তরের পরে) তাই cls.create() কল ব্যর্থ হবে। আপনি @nocollapse টীকা দিয়ে এটি এড়াতে পারেন:
    class A {
      /** @nocollapse */
      static create() {
        return new A();
      }
    }
    class B {
      /** @nocollapse */
      static create() {
        return new A();
      }
    }
    
  • সুপারক্লাস না জেনে স্ট্যাটিক পদ্ধতিতে সুপার ব্যবহার করা:

    নিম্নলিখিত কোড নিরাপদ, কারণ কম্পাইলার জানে যে super.sayHi() Parent.sayHi() :

    class Parent {
      static sayHi() {
        alert('Parent says hi');
      }
    }
    class Child extends Parent {
      static sayHi() {
        super.sayHi();
      }
    }
    Child.sayHi();
    

    যাইহোক, সম্পত্তি সমতলকরণ নিম্নলিখিত কোড ভঙ্গ করবে, এমনকি যদি myMixin(Parent).sayHi সমান হয় Parent.sayHi :

    class Parent {
      static sayHi() {
        alert('Parent says hi');
      }
    }
    class Child extends myMixin(Parent) {
      static sayHi() {
        super.sayHi();
      }
    }
    Child.sayHi();
    

    /** @nocollapse */ টীকা দিয়ে এই ভাঙ্গন এড়িয়ে চলুন।

  • Object.defineProperties বা ES6 গেটার/সেটার ব্যবহার করে:

    কম্পাইলার এই গঠনগুলি ভালভাবে বোঝে না। ES6 গেটার এবং সেটার্স ট্রান্সপিলেশনের মাধ্যমে Object.defineProperties(...) এ রূপান্তরিত হয়। বর্তমানে, কম্পাইলার স্থিরভাবে এই গঠন বিশ্লেষণ করতে অক্ষম এবং অনুমান করে যে বৈশিষ্ট্য অ্যাক্সেস এবং সেট পার্শ্ব প্রতিক্রিয়া মুক্ত। এর বিপজ্জনক প্রতিক্রিয়া হতে পারে। উদাহরণ স্বরূপ:

    class C {
      static get someProperty() {
        console.log("hello getters!");
      }
    }
    var unused = C.someProperty;
    

    এতে সংকলিত হয়:

    C = function() {};
    Object.defineProperties(C, {a: // Note someProperty is also renamed to 'a'.
      {configurable:!0, enumerable:!0, get:function() {
        console.log("hello world");
        return 1;
    }}});
    

    C.someProperty এর কোন পার্শ্বপ্রতিক্রিয়া নেই বলে স্থির করা হয়েছিল তাই এটি সরানো হয়েছে।