Skip to content

Instantly share code, notes, and snippets.

@leahgarrett
Last active May 28, 2019 00:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leahgarrett/6e9cb2263fee8da19a8a38034e00cf4f to your computer and use it in GitHub Desktop.
Save leahgarrett/6e9cb2263fee8da19a8a38034e00cf4f to your computer and use it in GitHub Desktop.
Event Loop

Event Loop

JavaScript itself is a single threaded language so in the traditional sense it is a blocking language.

One Thread == One Call Stack == One Thing At A Time
    - Philip Roberts

When we are running blocking code nothing else can be ran. Think about this in terms of the browser.

  1. Its a bad user experience if a user has to sit and wait for each thing to load in sequence.
  2. The browser wants to constantly render (every 6 milli seconds). If we are blocking that then nothing can re-render and looks like the browser has frozen.

Run this code and look at how the button seems frozen during execution.

<!DOCTYPE html>
<html>
<head>
</head>
<body>
    <button id="button">Click Me!</button>
    <script>
        function wait(ms) {
            let start = Date.now(),
            now = start;
            while (now - start < ms) {
                now = Date.now();
            }
        }

        document.getElementById("button").addEventListener("click", () => {
            wait(5000);
            alert("Ran!");
        });
    </script>
</body>
</html>

As you can see this is a very bad user experience and keeps us from doing else while we wait for our code to finish executing.

However we can make JavaScript act ansynchronously through the callback queue and event loop.

Non-Blocking or Asynchronous code is when a line of code is executed and the program is able to move on before that line of code has finished.

http://latentflip.com/loupe/


setTimeout

setTimeout(expression, timeout); runs the code/function once after the timeout.

console.log('start of js file');

setTimeout(function () {
    console.log('inside setTimeout');
}, 1000);

console.log('end of js file');

So it looks like the code was able to continue to execute while it waited for the timeout to hit 5 seconds.

If we modify the timeout to 0 seconds what do you believe the order printed to the screen will be?

The event is queued after the timeout.


setTimeout vs setInterval

setTimeout(expression, timeout); runs the code/function once after the timeout.

setInterval(expression, timeout); runs the code/function in intervals, with the length of the timeout between them.

console.log('start of js file');

setTimeout(function () {
    console.log('inside setTimeout');
}, 1000);

setInterval(function () {
    console.log('inside setInterval');
}, 500);

console.log('end of js file');

Mouse events

Mouse move fires everytime the mouse moves. Other events such as click are still fired and handled.

<!DOCTYPE html>
<html>
<head>
    <style>
        img {
            position: absolute;
            width: 100px;
            top: 0;
            left: 0;
        }
        body {
            height: 15000px;
        }
    </style>
</head>
<body>
    <h1>Welcome</h1>
    <p>This page is used for practicing DOM manipulation</p>
    <img src="https://avatars0.githubusercontent.com/u/583231?s=460&v=4">
    <div class="notice">Nothing to notice.</div>
    <script>

        let heading = document.querySelector("h1");
        let image = document.querySelector("img");
        window.addEventListener("click", function (event) {
            event.preventDefault();
            heading.innerHTML += "!";
            console.log('test')
        });

        let moveCounter = 0;
        window.addEventListener("mousemove", function (event) {
            console.log(`${moveCounter++}. moving ${event.screenX} ${event.screenY}`)
            image.style.top = event.clientY + 'px'
            image.style.left = event.clientX + 'px'
        });

    </script>
</body>
</html>

Debouncing and throttling

Debouncing can improve user experience by restricting the number of calls made to the server. For example calling to the server as a user types in something can result in the screen appearing to freeze eg: five characters entered could mean five separate requests that take 500ms. Debouncing and reducing the number of requests can prevent this.

Mouse move generates a lot of events. Do we need all those events?

We could act on one in 3 events instead.

    window.addEventListener("mousemove", function (event) {
        moveCounter++;
        if ((moveCounter % 3) == 0) {
            console.log(`${moveCounter}. moving ${event.screenX} ${event.screenY}`)
            image.style.top = event.clientY + 'px'
            image.style.left = event.clientX + 'px'
        }
    });

See Also Debouncing and Throttling Explained - on CSS Tricks


Videos for more information on the event loop

What the heck is the event loop anyway?
Further Adventures of the Event Loop - Erin Zimmer - JSConf EU 2018


Challenge

  1. Refactor the code into a separate javascript file
  2. Add a scroll event listener
  3. Display the location in a console.log message. Hint: use the following formula
var scrollLeft = (window.pageXOffset !== undefined) ? 
        window.pageXOffset : 
        (document.documentElement || document.body.parentNode || document.body).scrollLeft;
var scrollTop = (window.pageYOffset !== undefined) ? 
        window.pageYOffset : 
        (document.documentElement || document.body.parentNode || document.body).scrollTop;
  1. Use the scroll location to update the location of the image so it appears to stay next to the mouse cursor as the window scrolls

  2. Experiment with throttling the scroll messages

Beast

Experiement with the event loop visualiser http://latentflip.com/loupe
Try adding the setTimer and setInterval as well event such as mouse move.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment