# BAB 2: Node.js Fundamental

## BAB 2: Node.js Fundamental

### 2.1 Pengenalan Node.js

#### 2.1.1 Apa itu Node.js?

Node.js adalah runtime environment JavaScript yang dibangun di atas V8 JavaScript engine Chrome. Node.js memungkinkan pengembang untuk menjalankan JavaScript di sisi server.

#### 2.1.2 Fitur Utama Node.js

1. Single-threaded dengan event loop
2. Non-blocking I/O
3. Event-driven programming
4. Cross-platform
5. Extensive package ecosystem (NPM)

#### 2.1.3 Arsitektur Node.js

```
Application (JavaScript)
      ↓
   Node.js
      ↓
 V8 Engine + libuv
      ↓
Operating System
```

### 2.2 NPM (Node Package Manager)

#### 2.2.1 Pengenalan NPM

NPM adalah package manager standar untuk Node.js yang memungkinkan developer untuk:

* Menginstal package/module
* Mengelola dependencies
* Menjalankan script
* Membagikan code

#### 2.2.2 Package.json

```json
{
  "name": "my-app",
  "version": "1.0.0",
  "description": "My Node.js application",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js",
    "test": "jest"
  },
  "dependencies": {
    "express": "^4.18.2",
    "mysql2": "^3.6.0"
  },
  "devDependencies": {
    "nodemon": "^3.0.1",
    "jest": "^29.6.0"
  }
}
```

#### 2.2.3 NPM Commands

```bash
# Inisialisasi project baru
npm init

# Inisialisasi dengan default values
npm init -y

# Install package
npm install express

# Install development dependency
npm install --save-dev nodemon

# Install package global
npm install -g nodemon

# Uninstall package
npm uninstall express

# Update packages
npm update

# List installed packages
npm list
```

#### 2.2.4 Semantic Versioning

Format: MAJOR.MINOR.PATCH

* Major: Perubahan yang tidak backward compatible
* Minor: Penambahan fitur yang backward compatible
* Patch: Bug fixes yang backward compatible

Contoh:

```json
{
  "dependencies": {
    "express": "^4.18.2",  // ^ = update minor dan patch
    "mysql2": "~3.6.0",    // ~ = update patch saja
    "moment": "2.29.4"     // exact version
  }
}
```

### 2.3 Asynchronous Programming

#### 2.3.1 Callbacks

```javascript
// Contoh callback
const fs = require('fs');

fs.readFile('file.txt', 'utf8', (err, data) => {
  if (err) {
    console.error('Error:', err);
    return;
  }
  console.log('Data:', data);
});

// Callback Hell (Anti-pattern)
fs.readFile('file1.txt', 'utf8', (err, data1) => {
  if (err) return console.error(err);
  fs.readFile('file2.txt', 'utf8', (err, data2) => {
    if (err) return console.error(err);
    fs.readFile('file3.txt', 'utf8', (err, data3) => {
      if (err) return console.error(err);
      console.log(data1, data2, data3);
    });
  });
});
```

#### 2.3.2 Promises

```javascript
// Membuat Promise
const myPromise = new Promise((resolve, reject) => {
  const success = true;
  if (success) {
    resolve('Operation successful');
  } else {
    reject(new Error('Operation failed'));
  }
});

// Menggunakan Promise
myPromise
  .then(result => console.log(result))
  .catch(error => console.error(error));

// Promise chaining
const fs = require('fs').promises;

fs.readFile('file1.txt', 'utf8')
  .then(data1 => {
    console.log(data1);
    return fs.readFile('file2.txt', 'utf8');
  })
  .then(data2 => {
    console.log(data2);
    return fs.readFile('file3.txt', 'utf8');
  })
  .then(data3 => {
    console.log(data3);
  })
  .catch(error => {
    console.error('Error:', error);
  });
```

#### 2.3.3 Async/Await

```javascript
// Async function
async function readFiles() {
  try {
    const data1 = await fs.readFile('file1.txt', 'utf8');
    const data2 = await fs.readFile('file2.txt', 'utf8');
    const data3 = await fs.readFile('file3.txt', 'utf8');
    
    console.log(data1, data2, data3);
  } catch (error) {
    console.error('Error:', error);
  }
}

// Parallel execution
async function readFilesParallel() {
  try {
    const [data1, data2, data3] = await Promise.all([
      fs.readFile('file1.txt', 'utf8'),
      fs.readFile('file2.txt', 'utf8'),
      fs.readFile('file3.txt', 'utf8')
    ]);
    
    console.log(data1, data2, data3);
  } catch (error) {
    console.error('Error:', error);
  }
}
```

### 2.4 Error Handling

#### 2.4.1 Try-Catch

```javascript
// Basic try-catch
try {
  const result = someFunction();
  console.log(result);
} catch (error) {
  console.error('Error:', error.message);
}

// Async try-catch
async function getData() {
  try {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Error fetching data:', error);
    throw error; // Re-throwing error
  }
}
```

#### 2.4.2 Custom Errors

```javascript
// Custom Error Class
class ValidationError extends Error {
  constructor(message) {
    super(message);
    this.name = 'ValidationError';
  }
}

// Menggunakan Custom Error
function validateUser(user) {
  if (!user.name) {
    throw new ValidationError('Name is required');
  }
  if (!user.email) {
    throw new ValidationError('Email is required');
  }
}

try {
  validateUser({ name: '', email: '' });
} catch (error) {
  if (error instanceof ValidationError) {
    console.error('Validation Error:', error.message);
  } else {
    console.error('Unknown Error:', error);
  }
}
```

#### 2.4.3 Error Events

```javascript
const EventEmitter = require('events');

class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();

// Error listener
myEmitter.on('error', (error) => {
  console.error('Error event:', error.message);
});

// Emit error
myEmitter.emit('error', new Error('Something went wrong'));
```

#### 2.4.4 Uncaught Exceptions

```javascript
// Handle uncaught exceptions
process.on('uncaughtException', (error) => {
  console.error('Uncaught Exception:', error);
  // Clean up resources
  process.exit(1);
});

// Handle unhandled promise rejections
process.on('unhandledRejection', (reason, promise) => {
  console.error('Unhandled Rejection:', reason);
});
```

### 2.5 Event-Driven Programming

#### 2.5.1 Events Module

```javascript
const EventEmitter = require('events');

class MyApp extends EventEmitter {
  constructor() {
    super();
    this.init();
  }

  init() {
    // Register event listeners
    this.on('start', () => {
      console.log('Application started');
    });

    this.on('data', (data) => {
      console.log('Received data:', data);
    });

    this.on('error', (error) => {
      console.error('Error:', error);
    });
  }

  start() {
    // Emit events
    this.emit('start');
    this.emit('data', { message: 'Hello World' });
  }
}

// Usage
const app = new MyApp();
app.start();
```

### Latihan

1. Buat program Node.js sederhana menggunakan async/await
2. Implementasi custom error handling
3. Buat event emitter untuk logging system
4. Praktikkan penggunaan NPM untuk mengelola dependencies

### Review

* Node.js memberikan kemampuan untuk menjalankan JavaScript di server
* NPM adalah tools penting untuk mengelola package dan dependencies
* Asynchronous programming adalah konsep kunci dalam Node.js
* Error handling yang baik penting untuk aplikasi yang robust
* Event-driven programming memungkinkan aplikasi yang reaktif
