Discussion 7

DSC 106: Introduction to Data Visualization

JavaScript Execution Order

Understanding function and variable execution

Example 1: Function Execution Order


console.log("Start");

function greet() {
    console.log("Hello!");
}

greet();

console.log("End");
                

Execution Order

  • Step 1: "Start" is logged.
  • Step 2: `greet()` is called.
  • Step 3: "Hello!" is logged.
  • Step 4: `greet()` finishes execution.
  • Step 5: "End" is logged.

Run Example

Hoisting and Variable Scope

Understanding how JavaScript handles variables

Example 2: Hoisting in JavaScript


console.log(myVar); // undefined
var myVar = 10;
console.log(myVar); // 10
                

What Happens Internally?


// JavaScript Hoists Declarations
var myVar;
console.log(myVar); // undefined
myVar = 10;
console.log(myVar); // 10
                

Hoisting with let & const


console.log(myLet); // ReferenceError
let myLet = 20;
console.log(myLet);
                

Why? `let` and `const` do not initialize until execution reaches the declaration (Temporal Dead Zone).

Execution Order

  • Step 1: `var` is hoisted but uninitialized (`undefined`).
  • Step 2: `console.log(myVar)` prints `undefined`.
  • Step 3: `myVar` is assigned `10`.
  • Step 4: `console.log(myVar)` prints `10`.

Order of Function Execution

Understanding the Call Stack

Example 3: Call Stack Execution


function first() {
    console.log("First");
    second();
    console.log("First End");
}

function second() {
    console.log("Second");
}

console.log("Start");
first();
console.log("End");
                

How the Call Stack Works

  • Step 1: `"Start"` is logged.
  • Step 2: `first()` is called → added to the Call Stack.
  • Step 3: `"First"` is logged.
  • Step 4: `second()` is called → added to the Call Stack.
  • Step 5: `"Second"` is logged, `second()` finishes.
  • Step 6: `"First End"` is logged, `first()` finishes.
  • Step 7: `"End"` is logged.

Call Stack in Action

The Call Stack follows Last-In, First-Out (LIFO).


// Stack Operations
CALL: first() -> adds to stack
CALL: second() -> adds to stack
RETURN: second() -> removes from stack
RETURN: first() -> removes from stack
                

Understanding Async/Await in JavaScript

How async functions work and why they are useful

1. What is Async/Await?

  • async functions return a **Promise**.
  • await pauses execution until the Promise resolves.
  • Makes asynchronous code **look synchronous**.
  • Reduces callback hell and improves readability.

2. How Async/Await Works


			async function fetchData() {
				let response = await fetch("https://jsonplaceholder.typicode.com/todos/1");
				let data = await response.json();
				console.log(data);
			}
			
			fetchData();
							

Key Point: `await` makes JavaScript wait for the fetch request to complete.

3. Converting Promises to Async/Await


			// Using Promises
			fetch("https://jsonplaceholder.typicode.com/todos/1")
				.then(response => response.json())
				.then(data => console.log(data))
				.catch(error => console.error(error));
			
			// Using Async/Await
			async function fetchData() {
				try {
					let response = await fetch("https://jsonplaceholder.typicode.com/todos/1");
					let data = await response.json();
					console.log(data);
				} catch (error) {
					console.error(error);
				}
			}
			
			fetchData();
							

Why use Async/Await? More readable, avoids deeply nested `.then()` calls.

4. Handling Errors in Async/Await


			async function fetchData() {
				try {
					let response = await fetch("https://invalid-url.com/data");
					if (!response.ok) throw new Error("Failed to fetch data");
					let data = await response.json();
					console.log(data);
				} catch (error) {
					console.error("Error:", error.message);
				}
			}
			
			fetchData();
							

Tip: Always use `try/catch` to handle errors properly.

5. Real-World Use Case

Async/Await is useful for:

  • Fetching API data
  • Database queries
  • Processing large datasets asynchronously
  • Handling user authentication flows

Order of Execution in Promises and Async Operations

Understanding the JavaScript Event Loop

Example 4: Promises and Async Execution


console.log("Start");

setTimeout(() => console.log("Inside setTimeout"), 0);

Promise.resolve().then(() => console.log("Promise resolved"));

console.log("End");
                

Execution Order Breakdown

  • Step 1: `"Start"` is logged (synchronous code).
  • Step 2: `setTimeout` is called (sent to Web API).
  • Step 3: `Promise.resolve()` is called (sent to Microtask Queue).
  • Step 4: `"End"` is logged (synchronous code finishes).
  • Step 5: Microtask Queue executes → `"Promise resolved"` is logged.
  • Step 6: Macrotask Queue executes → `"Inside setTimeout"` is logged.

JavaScript Event Loop

The Event Loop processes tasks in this order:

  1. Execute all synchronous code (Call Stack).
  2. Process Microtask Queue (Promises, `queueMicrotask`).
  3. Process Macrotask Queue (`setTimeout`, `setInterval`).

Order of Execution in Data Loading

Fetch API & Promises in JavaScript

Example 5: Fetch & Promises Execution


console.log("Start");

fetch("https://jsonplaceholder.typicode.com/todos/1")
    .then(response => response.json())
    .then(data => console.log("Data Loaded:", data));

console.log("End");
                

Execution Order Breakdown

  • Step 1: `"Start"` is logged (synchronous execution).
  • Step 2: `fetch()` is called, sending request to **Web APIs**.
  • Step 3: `"End"` is logged (synchronous execution continues).
  • Step 4: Once the request completes, **Microtask Queue** processes `.then()`.
  • Step 5: `"Data Loaded:"` is logged with the fetched JSON response.

Fetch Execution in the Event Loop

The Event Loop processes **fetch requests** as follows:

  1. Execute **synchronous code** (Call Stack).
  2. Send **fetch request** to **Web API**.
  3. Continue executing **remaining synchronous code**.
  4. When fetch completes, add `.then()` callback to **Microtask Queue**.
  5. Execute **Microtask Queue** before Macrotasks.

Function Structure in JavaScript

Understanding JavaScript Function Syntax and Execution

1. Basic Function Syntax


function greet(name) {
    return "Hello, " + name + "!";
}

console.log(greet("Alice"));
                

Key Points: Uses `function` keyword, takes parameters, and returns a value.

2. Arrow Functions


const add = (a, b) => a + b;

console.log(add(2, 3)); // 5
                

Why use arrow functions? Shorter syntax, lexical `this` binding.

3. Function Expressions


const multiply = function(a, b) {
    return a * b;
};

console.log(multiply(4, 5)); // 20
                

Key Difference: Function expressions are assigned to variables and cannot be called before their definition.

4. Higher-Order Functions


function operate(a, b, operation) {
    return operation(a, b);
}

console.log(operate(10, 5, (x, y) => x - y)); // 5
                

Functions that take other functions as arguments or return functions.

Where to Place Functions in JavaScript

Best Practices for Structuring Code

1. Global vs. Local Scope


			// Global Function (Avoid excessive usage)
			function globalFunction() {
				console.log("I am global!");
			}
			
			// Local Function (Scoped inside another function)
			function localScope() {
				function innerFunction() {
					console.log("I am local!");
				}
				innerFunction();
			}
							

Best Practice: Keep functions local unless they need global access.

2. Separating Logic, Handlers, and API Calls


			// Business Logic (Pure Functions)
			function calculateTotal(price, tax) {
				return price + (price * tax);
			}
			
			// Event Handler (DOM Interaction)
			document.getElementById("buyBtn").addEventListener("click", () => {
				alert("Purchase successful!");
			});
			
			// API Call Function
			async function fetchData() {
				let response = await fetch("https://jsonplaceholder.typicode.com/todos/1");
				let data = await response.json();
				console.log(data);
			}
							

Best Practice: Keep logic, event handlers, and API calls separate.

3. The Module Pattern


			const ShoppingCart = (function() {
				let cart = [];
			
				function addItem(item) {
					cart.push(item);
					console.log(cart);
				}
			
				return {
					add: addItem
				};
			})();
			
			ShoppingCart.add("Laptop");
							

Why? Prevents polluting global scope and maintains data encapsulation.

4. Using ES6 Modules


			// utils.js (Exporting Functions)
			export function add(a, b) {
				return a + b;
			}
			
			// main.js (Importing Functions)
			import { add } from './utils.js';
			console.log(add(2, 3)); // 5
							

Why? Helps maintain modular, reusable code.

5. Where to Put Functions in a Project


			// File Structure
			/project-root
			  /js
				/modules
				  cart.js
				  user.js
				/utils
				  helpers.js
			  app.js
			  index.html
							

Tip: Place functions inside appropriate folders to keep code maintainable.

Common Workflow for Interactive D3.js Visualizations

Step-by-step guide to building interactive charts

1. Setting Up a D3 Visualization


// Select the container and append an SVG
const svg = d3.select("body").append("svg")
    .attr("width", 500)
    .attr("height", 300);

console.log("SVG created!");
                

Why? Every D3 visualization starts with an svg container.

2. Binding Data to Elements


const data = [10, 30, 50, 70, 90];

// Bind data and create circles
svg.selectAll("circle")
    .data(data)
    .enter()
    .append("circle")
    .attr("cx", d => d)
    .attr("cy", 100)
    .attr("r", 10)
    .attr("fill", "blue");
                

Why? D3 binds data to DOM elements dynamically.

3. Adding Scales and Axes


const xScale = d3.scaleLinear()
    .domain([0, 100])
    .range([0, 400]);

const xAxis = d3.axisBottom(xScale);

svg.append("g")
    .attr("transform", "translate(50, 200)")
    .call(xAxis);
                

Why? Scales map data values to screen coordinates.

4. Creating Interactive Elements


svg.selectAll("circle")
    .on("mouseover", function() {
        d3.select(this).attr("fill", "red");
    })
    .on("mouseout", function() {
        d3.select(this).attr("fill", "blue");
    });
                

Why? Event listeners make visualizations interactive.

5. Adding Transitions and Animations


svg.selectAll("circle")
    .transition()
    .duration(1000)
    .attr("r", 20);
                

Why? Smooth animations enhance user experience.

Examples of D3.js Visualizations

Real-world interactive visualizations made with D3

1. D3 Visualization Gallery

A curated gallery of different D3.js visualizations.

View Gallery

2. England & Wales Baby Names

An interactive visualization of baby name trends.

Explore Visualization

3. 512 Paths to the White House

A famous election visualization from The New York Times.

View Interactive Graphic

4. CodePen D3 Examples

Explore hundreds of D3.js visualizations on CodePen.

Browse CodePen D3 Examples

5. Step-by-Step D3 Examples

Learn how to build interactive D3 charts step by step.

View Tutorial