sxg1-b3Ehttps://www.corewebvitals.io/pagespeed/14-methods-to-defer-javascript乻ig;sig=*MEUCIQChV/aX8t2XzGvRaqkGw3wlxOvJjKc0kxmL+e9hUiNT/gIgJcBTYW0JRkiA02yR/GQtPxo5saYgnllTPugm8Sg6U/0=*;integrity="digest/mi-sha256-03";cert-url="https://www.corewebvitals.io/cdn-fpw/sxg/cert.pem.msg.LwfIG1e-2imTqolPnn7DI8P0tp-O04zMhn1HzZMjbLg";cert-sha256=*LwfIG1e+2imTqolPnn7DI8P0tp+O04zMhn1HzZMjbLg=*;validity-url="https://www.corewebvitals.io/cdn-fpw/sxg/valid.msg.validity";date=1718380347;expires=1718985147珼dateXFri, 14 Jun 2024 16:52:27 GMTDvaryOAccept-EncodingFcf-rayT893bd4b0b3eb9b47-HKGFdigestX9mi-sha256-03=7gYSNTRis2gUfjPRth9WlfHmUInXjfzPSiDxgZkmM+M=FserverJcloudflareG:statusC200GexpiresXSat, 15 Jun 2024 16:52:27 GMTLcontent-typeXtext/html; charset=UTF-8Mcache-controlNmax-age=691200Mlast-modifiedXFri, 14 Jun 2024 16:52:27 GMTOcf-cache-statusDMISSPcontent-encodingLmi-sha256-03@

14 methods to defer or schedule JavaScript

Learn how to defer and schedule JavaScript

Arjen Karel Core Web Vitals Consultant
Arjen Karel
linkedin

Why defer or schedule JavaScript?

JavaScript can (and will) slow down your website in a few ways. This can have all sort of negative impact on the Core Web Vitals. JavaScript can compete for network resources, it can compete for CPU resources (block the main thread) and it can even block the parsing of a webpage. Deferring and scheduling your scripts can drastically improve the Core Web Vitals.

Table of Contents

  • Why defer or schedule JavaScript?
  • How can JavaScript timing affect the Core Web Vitals?
  • How to choose the right defer method?
  • Method 1: Use the defer attribute
  • Method 2: Use the async attribute
  • Method 3: Use modules
  • Method 4: Place scripts near the bottom of the page
  • Method 5: Inject scripts
  • Method 6: Inject scripts at a later time
  • Method 7: Change the script type (and then change it back)
  • Method 9: Use readystatechange
  • Method 10: Use setTimeout with no timeout
  • Method 11: Use setTimeout with a timeout
  • Method 12 Use a promise to set a microtask
  • Method 13 Use a microtask
  • Method 15: Use postTask

To minimize the nasty effects that JavaScript can have on the Core Web Vitals it is usually a good idea to specify when a script gets queued for downloading and schedule when it can take up CPU time and block the main thread.

How can JavaScript timing affect the Core Web Vitals?

How can JavaScript timing affect the Core Web Vitals? Just take a look at this real life example. The first page is loaded with 'render blocking' JavaScript.  The paint metrics as well as the Time to interactive are pretty bad. The second example is of the the exact same page but with the JavaScript deferred. You will see the LCP image still took a big hit. The third example has the same script executed after the page 'load event' and has the function calls broken up into smaller pieces. This last one is passing the Core Web Vitals with room to spare.

js render blocking lhnull
js deferred lhnull
js after load lhnull


By default, external JavaScript in the head of the page will block the creation of the render tree. More specifically: when the browser encounters a script in the document it must pause DOM construction, hand over control to the JavaScript runtime, and let the script execute before proceeding with DOM construction. This will affect your Paint Metrics (Largest Contentful Paint and First Contentful Paint).

Deferred or async JavaScript can still impact paint metrics, especially the Largest Contentful Paint because it will execute, and block the main thread, once the DOM has been created (and common LCP elements like might not have been downloaded).

External JavaScript files will also compete for network resources. External JavaScript files are usually downloaded earlier then images. IF you are downloading too many scripts, the downloading of your images will be delayed.

Last but not least, JavaScript might block or delay user interaction. When a script is using CPU resources (blocking the main thread) a browser will not respond to input (clicks, scrolling etc) until that script has completed.

How does scheduling or deferring JavaScript fix the core web vitals?

Scheduling or deferring JavaScript does not fix the core web vitals per se. It is all about using the right tool for the right situation. As a rule you should try to delay your scripts as little as possible but queue them for download and execute them at the appropriate time.

How to choose the right defer method?

Not all scripts are the same and every script has it's own functionality. Some scripts are important to have early in the rendering process, others are not.

js defer vs async vs blockingnull

I like to categorize JavaScripts in 4 groups based on their level of importance.

1. Render critical. These are the scripts that will change the appearance of a web-page. If they do not load the page will not look complete. These scripts should be avoided at all costs. If you cannot avoid them for some reason they should not be deferred. For example a top slider or an A/B testing script.
2. Critical. These scripts will not change the appearance of a webpage (too much) but the page won't work well without them. These scripts should be deferred or asynced. For example your menu scripts.
3. Important. These are scripts that you want to load because they are valuable to you or the visitor. I tend to load these scripts after the load event has been fired. For example analytics or a 'back to top' button.
4. Nice to have. These are scripts that you can live without if you absolutely need to. I load these scripts with the lowest of priority and only execute them when the browser is idle. For example a chat widget or a facebook button.

Method 1: Use the defer attribute

Scripts with the defer attribute will download in parallel and are added to the defer JavaScript queue. Just before the browser will fire the DOMContentLoaded event all the scripts in that queue will execute in the order in which they appear in the document.

<script defer src='javascript.js'></script>

The 'defer trick' usually fixes a lot of issues, especially the paint metrics. Unfortunately there is no guarantee, it depends on the quality of the scripts. Deferred scripts will execute once all the scripts have been loaded and the HTML is parsed (DOMContentLoaded). The LCP element (usually a large image) might not be loaded by then and the deferred scripts will still cause a delay in the LCP.

When to use:

Use deferred scripts for Critical scripts that are needed as soon as possible.

Advantages:

  1. Deferred scripts will download in parallel
  2. The DOM will be available at execution time

Disadvantages:

  1. Deferred scripts might delay your LCP metrics 
  2. Deferred scripts will block the main thread once they are executed
  3. It might not be safe to defer scripts when inline or async scripts depend on them

Method 2: Use the async attribute

Scripts with the async attribute download in parallel and will execute immediately after they have finished downloading.

<script async src='javascript.js'></script>

Async scripts will do little to fix your pagespeed issues. It is great that they are downloaded in parallel but that is about it. Once they are downloaded they will block the main thread as they are executed.

When to use:

Use async scripts for Critical scripts that are needed as soon as possible and are self-contained (do not rely on other scripts).

Advantages:

  1. Async scripts will download in parallel.
  2. Async scripts will execute as soon as possible.

Disadvantages:

  1. DOMContentLoaded may happen both before and after async.
  2. The execution order of the script swill be unknown beforehand.
  3. You cannot use async scripts that rely on other async or deferred scripts

Method 3: Use modules

Modulair scripts are deferred by default unless they have they async attribute. In that case they will be treated like async scripts

<script module src='javascript.js'></script>

Modules are a new way of thinking about JavaScript and fix some design flaws. Other than that using script modules will not speed up your website. 

When to use:

When your application is build in a modulair way it makes sense to also use JavaScript modules.

Advantages:

  1. Modules are deferred by default
  2. Modules are easier to maintain and work great with modulair web design
  3. Modules allow easy code splitting with dynamic imports where you only import the modules that you need at a certain time.

Disadvantages:

  1. Modules themselves will not improve the Core Web Vitals
  2. Importing modules just-in-time or on the fly might be a slow and worsen the FID and INP 

Method 4: Place scripts near the bottom of the page

Footer scripts are queued for download at a later time. This will prioritize other resources that are in the document above the script tag.

<html>
   <head></head>
   <body>
      [your page contents here]
      <script defer src='javascript.js'></script>
   </body>
</html>

Placing your scripts at the bottom of the page is an interesting technique. This will schedule other resources (like images) ahead of your scripts. This will increase the chance that they are available to the browser and painted on the screen before the JavaScript files have finished downloading and the main thread will be blocked by script execution. Still ... no guarantee.

When to use:

When your scripts are already performing quite well but you want to slightly prioritize other resources like images and webfonts.

Advantages:

  1. Placing scripts at the bottom of the page does not require much knowledge.
  2. If done correctly there is not risk that this will break your page

Disadvantages:

  1. Critical scripts might get downloaded and executed later
  2. It does not fix any underlying JavaScript issues

Method 5: Inject scripts

Injected scripts are treated like async scripts. They are downloaded in parallel and are executed immediately after downloading.

<script>
    const loadScript = (scriptSource) => {
        const script = document.createElement('script');
        script.src = scriptSource;
        document.head.appendChild(script);
    }
    
    // call the loadscript function that injects 'javascript.js'
    loadScript('javascript.js');
</script>

From a Core Web Vitals perspective this technique is exactly the same as using <script async>.

When to use:

This method is often used by third party scripts that trigger as early as possible. The function call makes it easy to encapsulate and compress code.

Advantages:

  1. Contained, code that injects an async script.

Disadvantages:

  1. DOMContentLoaded may happen both before and after the script has loaded.
  2. The execution order of the script swill be unknown beforehand.
  3. You cannot use this on scripts that rely on other async or deferred scripts

Method 6: Inject scripts at a later time

Nice-to-have scripts should in my opinion never be loaded deferred. They should be injected injected at the most opportune moment. In the example below the script will execute after the browser has send the 'load' event.

<script>
window.addEventListener('load', function () {
  // see method 5 for the loadscript function
  loadScript('javascript.js');
});
</script>

This is the first technique that will reliably improve the Largest Contentful paint. All important resources, including images will be downloaded when the browser fires the 'load event'. This might introduce all sorts of issues because it might take a long time for the load event to be called.

When to use:

For nice-to-have scripts that have no reason to impact the paint metrics.

Advantages:

  1. Won't compete for critical resources because it will inject the script once the page and it's resources have loaded

Disadvantages:

  1. If your page is poorly designed Core Web Vitals wise it might take a long time for the page to send the 'load' event
  2. You need to be careful not to apply this to critical scripts (like lazy loading, menu etc)

Method 7: Change the script type (and then change it back)

If a script tag is found somewhere on the page that 1. has a type attribute and 2. the type attribute is not "text/javascript" the script will not be downloaded and executed by a browser. Many JavaScript Loaders (like CloudFlare's RocketLoader) rely on his principle. The idea is quite simple and elegant.

First all scripts are rewritten as this:

<script type="some-cool-script-type" src="javascript.js"></script>

Then, at some point during the loading process these scripts are converted back to 'normal javascripts'.

When to use:

This is not a method I would recommend. Fixing JavaScript impact will take a lot more then just moving every script a bit further down the queue. On the other hand, If you have little control over the scripts running on the page or have insufficient JavaScript knowledge this might be your best bet.

Advantages:

  1. It is easy, just enable rocket loader or another plugin and all your scrips are now executed at a somewhat later time.
  2. IT will probably fix your paint metrics provided you did not use JS based lazy loading.
  3. It will work for inline and external scripts.

Disadvantages:

  1. You will have no fine-grained control over when the scripts execute
  2. Poorly written script might break
  3. It uses JavaScript to fix JavaScript
  4. It does nothing to fix long running scripts

Method 8: Use the intersection observer

With the intersection observer you can execute a function (which in this case loads an external JavaScript) when an element scrolls into the visible viewport.

<script>
const handleIntersection = (entries, observer) => {
    if (entries?.[0].isIntersecting) {
        // load your script or execute another 
           function like trigger a lazy loaded element
        loadScript('javascript.js');

        // remove the observer
        observer.unobserve(entries?.[0].target);
    }
};
const Observer = new window.IntersectionObserver()
Observer.observe(document.querySelector('footer'));
</script>

This is by far the most effective method of deferring JavaScript there is. Only load the scripts that you need, just before you need them. Unfortunately real life is hardly even this clean and not many scripts can be bonded to an element that scrolls into view.

When to use:

Use this technique as much as possible! Whenever a script only interacts with an off-screen component (like a map, a slider, a form) this is the best way to inject this script.

Advantages:

  1. Will noA╢d({鎓€?霠樍欢嶛 z鞁tjt interfere with Core Web Vitals LCP and FCP
  2. Will never inject scripts that are not used. This will improve the FID and INP

Disadvantages:

  1. Should not be used with components that might be in the visible viewport
  2. Is harder to maintain then basic <script src="...">
  3. Might introduce a layout shift

Method 9: Use readystatechange

document.readystate can be used as and alternative to the 'DOMContentloaded' and 'load' event. The 'interactive' readystate is usually a good place to call critical scripts that need to change the DOM or addenthandlers. 
The 'complete' ready state is a good place to call scripts that are less critical.

document.addEventListener('readystatechange', (event) => {
  if (event.target.readyState === 'interactive') {
    initLoader();
  } else if (event.target.readyState === 'complete') {
    initApp();
  }
});

Method 10: Use setTimeout with no timeout

setTimeout is a frowned-upon yet heavily underestimated method in the pagespeed community. setTimeout has gotten a bad wrap because it is often misused.  Many developers believe setTimeout can only be used to to delay script execution by the set amount of milliseconds. While this is true setTimeout actually does something far more interesting. It creates a new task at the end of the the browsers event loop. This behavior can be used to schedule your tasks effectively. It can also be used to break up long tasks into separate smaller tasks

<script>
   setTimeout(() => {
       // load a script or execute another function
       console.log('- I am called from a 0ms timeOut()')
    }, 0);

   console.log('- I was last in line but executed first')
/* Output: - I was last in line but executed first - I am called from a 0ms timeOut() */ </script>

When to use:

setTimeout created a new task in the browsers event loop. Use this when your main thread is being blocked by many function calls that run sequentially.

Advantages:

  1. Can break up long running code into smaller pieces.

Disadvantages:

  1. setTimeout is as rather crude method and does not offer prioritization for important scripts.
  2. Will add the to-be-executed code at the end of the loop

Method 11: Use setTimeout with a timeout

Things get even more interesting when we call setTimeout with a timeout of more then 0ms

<script>
   setTimeout(() => {
       // load a script or execute another function
       console.log('- I am called from a 10ms timeOut()')
    }, 10);

   setTimeout(() => {
       // load a script or execute another function
       console.log('- I am called from a 0ms timeOut()')
    }, 0);

   console.log('- I was last in line but executed first')
/* Output: - I was last in line but executed first - I am called from a 0ms timeOut() - I am called from a 10ms timeOut() */ </script>

When to use:

When you need an easy method to schedule one script after another a small timeout will do the trick

Advantages:

  1. Supported on all browsers

Disadvantages:

  1. Does not offer advanced scheduling

Method 12 Use a promise to set a microtask

Creating a micro-task is also an interesting way of scheduling JavaScript. Micro-tasks are scheduled for execution immediately after the current execution loop has finished.

<script>
   const myPromise = new Promise((resolve, reject) => {
      resolve();
   }).then(
      () => {       
         console.log('- I was scheduled after a promise')
         }
   );
console.log('- I was last in line but executed first') /* Output: - I was last in line but executed first - I was scheduled after a promise */ </script>

When to use:

When a task needs to be scheduled immediately after another task. 

Advantages:

  1. The microtask will be scheduled immediately after the task has finished running.
  2. A microtask can be used to delay less important pieces of JavaScript code in the same event. 

Disadvantages:

  1. Will not break up the main thread input smaller part. The browser will have no chance to respond to user input.
  2. You will probably never need to use microtasks to improve the Core Web Vtials unless you allready know exactly what you are doing.

Method 13 Use a microtask

The same result can be achieved by using queueMicrotask(). The advantage of using queueMicrotask() over a promise is that is is slightly faster and you do not need to handle your promisses.

<script>
   queueMicrotask(() => {
      console.log('- I am a microtask')
   })
     
   console.log('- I was last in line but executed first')

   /*
      Output:
      - I was last in line but executed first
      - I am a microtask
   */
</script>


Method 14: Use requestIdleCallback

The window.requestIdleCallback() method queues a function to be called during a browser's idle periods. This enables developers to perform background and low priority work on the main event loop, without impacting latency-critical events such as animation and input response. Functions are generally called in first-in-first-out order; however, callbacks which have a timeout specified may be called out-of-order if necessary in order to run them before the timeout elapses.

<script>
requestIdleCallback(() => {
    const script = document.createElement('script');
    script.src = 'javascript.js';
    document.head.appendChild(script);
});
</script>

When to use:

Use this for scripts that are Nice to have or to handle non-critical tasks after user input

Advantages:

  1. Execute JavaScript with minimal impact to the user
  2. Will most probably improve FID and INP

Disadvantages:

  1. Supported in most browsers but not all. There are poly-fills out there that fallback on setTimeout();
  2. No guarantee the code will ever fire 

Method 15: Use postTask

The method allows users to optionally specify a minimum delay before the task will run, a priority for the task, and a signal that can be used to modify the task priority and/or abort the task. It returns a promise that is resolved with the result of the task callback function, or rejected with the abort reason or an error thrown in the task.

<script>
scheduler.postTask(() => {
    const script = document.createElement('script');
    script.src = 'javascript.js';
    document.head.appendChild(script);
}, { priority: 'background' });
</script>

When to use:

postTask is the perfect API to schedule script with. Unfortunately browser support at this time as bad so you should not use it.

Advantages:

  1. Complete controle over JavaScript execution scheduling!

Disadvantages:

  1. Not supported in some important browsers.
14 methods to defer or schedule JavaScriptCore Web Vitals 14 methods to defer or schedule JavaScript

两个鬼故事钥匙管理制度幻想三国志2剧情易经起名网公司起名字艳之夜瘦金书家纺店铺起名集哪家好女装公司起名大全新办企业起名我的仙女分身彩峰快印e轮回杰克奥特曼国语金庸群侠传5少年的你百度云孔雀开屏是什么意思八字强怎么起名大长今国语版全集免费起名网页大全幼教公司起名属鼠起名的忌讳中老年服装店起名大全金桂飘香造句钟姓鼠年宝宝起名大全起重机证考试报名oracle9i下载兄弟俩人公司起名医疗器械公司名称大全起名大全钱的化身演员表师父是全派的炉鼎影响力在线阅读少年生前被连续抽血16次?多部门介入两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”淀粉肠小王子日销售额涨超10倍高中生被打伤下体休学 邯郸通报单亲妈妈陷入热恋 14岁儿子报警何赛飞追着代拍打雅江山火三名扑火人员牺牲系谣言张家界的山上“长”满了韩国人?男孩8年未见母亲被告知被遗忘中国拥有亿元资产的家庭达13.3万户19岁小伙救下5人后溺亡 多方发声315晚会后胖东来又人满为患了张立群任西安交通大学校长“重生之我在北大当嫡校长”男子被猫抓伤后确诊“猫抓病”测试车高速逃费 小米:已补缴周杰伦一审败诉网易网友洛杉矶偶遇贾玲今日春分倪萍分享减重40斤方法七年后宇文玥被薅头发捞上岸许家印被限制高消费萧美琴窜访捷克 外交部回应联合利华开始重组专访95后高颜值猪保姆胖东来员工每周单休无小长假男子被流浪猫绊倒 投喂者赔24万小米汽车超级工厂正式揭幕黑马情侣提车了西双版纳热带植物园回应蜉蝣大爆发当地回应沈阳致3死车祸车主疑毒驾恒大被罚41.75亿到底怎么缴妈妈回应孩子在校撞护栏坠楼外国人感慨凌晨的中国很安全杨倩无缘巴黎奥运校方回应护栏损坏小学生课间坠楼房客欠租失踪 房东直发愁专家建议不必谈骨泥色变王树国卸任西安交大校长 师生送别手机成瘾是影响睡眠质量重要因素国产伟哥去年销售近13亿阿根廷将发行1万与2万面值的纸币兔狲“狲大娘”因病死亡遭遇山火的松茸之乡“开封王婆”爆火:促成四五十对奥巴马现身唐宁街 黑色着装引猜测考生莫言也上北大硕士复试名单了德国打算提及普京时仅用姓名天水麻辣烫把捣辣椒大爷累坏了

两个鬼故事 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化