# Async Code in Node.js: Callbacks vs Promises 

Node.js feels fast not because it does things instantly, but because it **does not wait**.

If you understand async code deeply, you unlock:

*   high-performance backend systems
    
*   scalable APIs
    
*   better debugging skills in interviews and real projects
    

This is not just theory — we will walk through how it actually works internally.

* * *

## Why Asynchronous Code Exists in Node.js

Node.js runs on a **single-threaded event loop**. That means:

*   One main thread handles all requests
    
*   No blocking is allowed if you want scalability
    

If Node.js waited for slow operations like file I/O or API calls, the entire server would freeze.

So instead, Node.js delegates heavy work to the system and continues execution.

* * *

### Event Loop Concept (Visual)

![Image](https://images.openai.com/static-rsc-4/7lzmHdJ60rC3bWsi4tAADiXdipQmMpOLrdb1H54fhMoJ4UM7IbGTlZdmAbi1lcXwuK4yfS-xGqywxz3FeeKEV7srlcp_XyxjO9oTMugDxHzhOGpH_5bLfTr5pSKVnTcnirj8swMv1aOGKxERDwwmCTlYekS9p86X1zSHNLbOJGW2hZLothXAYJ4BUYkGPS6j?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/dqdoCub2g6A0m-iTa7klaYZiXGP4EgNW1bl6tsxYIkatBzrNdIaXEprXlAdc9qSeUM5kX360Fw5ooJ4RXHKObWMZV7q01YX1ozqDJUpVCIePR5Ww-ePKpJOvRf_AvtnDKl9vL-NqHrsLSYIy5I4xtm76mZHO3wvQWakhrM0jYginPkCabdYr3EnTikmQ8SQ3?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/CEb0iuQQB2OfG5oaPIjwUwcWR01_hp4ji_tVu0aWnMfxcrjDH8gV5RWqCd_3RLv4SIPmpkyMi3IzeHxUdtYWJ-haqasqaJUVrFKstj3av-sUgluvxLrfELpBJzB2kEyecF5-VgDwRdIMq4tspET3Uub7FMBPZtdSNwC6r2fOaCNdCrrtvbQxTovpdnO0jD96?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/QPzQzFjjHyWuLNhPizg_7zD3kD0GVzl9YMCzFUiDlbwjwqExGO9yKBQC0qLz_sFq7v8tuH6oASR2NYBlkxOoWkWbBIRSyKONpGQcDK9qV2xCM_PDHKBuu8PNOqWFR3-dEkvbNIQi7aF0dtC-G3ooGgC3Wjb2Z5JEFCCeU4e9S7uscnu0yCXstBcRj6jooyhq?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/IOh7FKACX-MOUvqLBtXnHiBI69F2CkpLlQ9tXcU5vWOAGtm625ImnDV1UdxG3486_7ko_PFQ_gtGUbUqXxOMI7IvAJI1vhHFSfN0Re6psnJ1e647JBFBHVzeeS1mhswGK8144xLsb4NJQgZUcoAzx59E1qvKv3aXcwfO1I8T0B4WNynUMU83_3HHqAzu4kP3?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/Ion1thp5-CWTmHuDsvhEseUweMyExkOgaZwYkUomty9B6iHfODQp___emVFqc68LqmsIzeK7ENyIlKVqiIF1FugS4PZVsEmHeGhG4J4-ofI9i2qaZVt0I6Il563GJ-33uvzgtIDf1p0z1zmPuDEtSL2q00rSUsXQwIwS6t0XwtbhXMeqkjU_DT_gkKhXJdNR?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/YdxDO_trPm1xZc1ZgbTYYPm7Q4srsy1KKGqA4WM3_gYghH8AwU85ZrIIPZxguOrbrfHARVackBYox8q0R2qKEeGZjq5foaDtkt901I0ZEW189JIstWuUrAnv8Ma4LGUKoRGXXQPcQ29pPZm8cZ5aj0legqW00sClLyJGQrmeDsJGUx05lJSzbUinisA1u2Ev?purpose=fullsize align="center")

**Flow:**

1.  Task starts
    
2.  Async operation goes to background (libuv / OS)
    
3.  Event loop continues executing other code
    
4.  Callback queue stores completed tasks
    
5.  Event loop picks and executes them
    

* * *

## Real Scenario: File Reading (Blocking vs Non-Blocking)

### Blocking Version

```js
const fs = require('fs');

const data = fs.readFileSync('file.txt', 'utf-8');
console.log(data);
console.log("Next step");
```

Problem:

*   Execution stops until file is fully read
    
*   No concurrency
    

* * *

### Non-Blocking Version (Callback)

```js
const fs = require('fs');

fs.readFile('file.txt', 'utf-8', (err, data) => {
    if (err) throw err;
    console.log(data);
});

console.log("Next step");
```

Output order:

```plaintext
Next step
(file content later)
```

* * *

## Callback Execution Flow (Step-by-Step)

![Image](https://images.openai.com/static-rsc-4/b9MpVWBUfuVdZkWjp30nX4jP7x93l6VYxke7OUTKtRs-J_9OzzLf1_HdeXt-9gB8twXVtA29mByXuzdA_pJASEW1aIfejmTvlsiNGi5MsaDzGnTVIbcLeGGwgzcgJq9o1T-YbUZ9ZcjEYaT2W4YZ3IBXMcfFTAwFIh8SMsbqcblQzb6gxJ-T-9vR6qtbOJav?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/7HaxD9K8vacOw-WVQn9XH2hDSshHGLGv2tvV-6IpDFX_Gj1IrEDTBbiKDZSm1s0SJa3fxBvnIAQw5tgY9u7wHbmrq3w8he6En6DhDib93X0jmtZVCLJ6hx20tIzae713IwWZSigCh_qtBdmTwoc8RUbudbPkjksHBlUsu9mHXgA51bpxogCANdm4jv0_K89M?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/mXn10nWkC2Pjub-BG_tWS_OKWUM3tbJwUYpu7JS7Sc5s50pggr1yBdjAposb4GK8xzEnhD9oMzB8Tni3kMnF2USJv7kVDbEOzvNBPzRiuvAFiuQMIhR1Hgq4dIQTc_US6FD76KDGqDpvv5mu1o7Es7z3TCgt2KUGw1SPL_1hyqWPOlp39_a20836kucWC4uc?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/e24_s20S_1IT8fEWygRr_YoF45VGSrOdFQ9WUsEtgQalftY8-GA69jVP7cIAub2Jk8esgfruO_QrGzZAe03EIDLiZwE-eVi3QiuKKDe6oWE_ZhbUAIP-hAUCV3wuXestePE17dTxCJ9BbnaIUXCzybxSagGLWkO9asydVsVA_6QFqg4RRYKEjmyfhujSYVhd?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/Ku9r-Hp3g9g7ag4HNHUEkDgmrrv-CxiwTG9irwZOZulDwI9hQTsqE1sPrvUaH_KK0xsDbnrjN-rQTF_Mg3vJkWtFcg4lxqa0HyUfqgzVIuH01d-w8Z-SlpUkBNtwpRcdUJCcnEPhwWZ0EcYnPl-GXdEXGyXrkcNWekupT-8LY6F4fBommJnpZdS_D4cM-SDh?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/h7gSkCEHg_RIazWnocWWSB5Ozbg_vXwjEDsPKdO_FG8_dwP2GsbmaXVbZfu8s-9YVgyCBtsRZxf9FQO-4ikEp-d4Gr03zKgmwJdY_-LIZp1UNKjVww5Bbi12cdYV48T6D1vtDplUfA15uWOy0i-L96TYOEzhy-0rb7oeWyHRzRUyQ2rjykjx-UYsotOo1Hw4?purpose=fullsize align="center")

1.  `readFile` is called
    
2.  Node.js sends file task to system
    
3.  Main thread continues
    
4.  Once file is ready → callback pushed to queue
    
5.  Event loop executes callback
    

This is the foundation of Node.js scalability.

* * *

## The Real Problem: Callback Hell

As systems grow, you rarely have just one async operation.

```js
fs.readFile('file1.txt', 'utf-8', (err, data1) => {
    fs.readFile('file2.txt', 'utf-8', (err, data2) => {
        fs.readFile('file3.txt', 'utf-8', (err, data3) => {
            console.log(data1, data2, data3);
        });
    });
});
```

* * *

### Callback Hell Visualization

![Image](https://images.openai.com/static-rsc-4/8Cd6i02mNhsuPjA4YDQTwNPayIKortHGs1uZrzMTFUKkpv31GB5T68BVf2_SnHoBEMOTzgrKy3AbywjKaKsxw3dhQP0FMzZF8TC4cr6990kjmuDaavD2Hl9G2GO8Pg2TTHppJwW2vFq_B2JMDYQNwMBtL2VddoPcfVqaMCw7ydXR4iDwMLaAVb_4cZCdEeqQ?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/sybX0OJlvHsUnl_dViiR4SwlLt2AL05IPA8db-xtdAX7aaP0K_akSTUWVLxL-PYw2tkU86ojyemtN1c9VLKSPQX9uXBwJOdLH_iX0RR4KYjct0rb_Q_f0uh8EHhik1tqd-s2pOwIDANZvMdXERqdY0kPvS-zrw4GwwgEkwAILWAiA_tsLpg8aaHpdnVWT01L?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/90kxZK1hOlc8pL4LE03JUAwikQdTp2WcyXsA0bbQmynCBLGASTerCur2eGUc1Ldwvbn2IoRcdKa6iV8kffhDNjlkQBbyH10a8ET5TOrK5oKqabAntbwt2dT86LLqVz4xcvvmcAWslj77P8a6SRRZiG4PDEPfAodFuMBKvt3D6d_mOnaX-7_vx4L-r-nxHWbD?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/oweub5Wm2qySQXkWadYxXHFE9Ugw-yrvNEX1GsyyR2nKwpA97vedQAWpAeRGBImJACW-WWoe3-LuyDuTxDDvVKhHj2uDcX4kBFp64tARasZ-eF_ugE80hveTsqzs357OlpjfW3xLKOaiPXsyHnzY2c4kNvmwRNMvM3dmCcInY0z4aJ9ebClbot2NEDmQB2XJ?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/3xDPOM5FVawmxuBIMo4QGWkPv7coG3ZQFAtel8THBv4ptlnyOv725SzBlTYYYR963YvqOvkhWXE_q_Nmf9w8_GVhGFud4HXRxGUV-tpwMr-oIUmLnkFj765Y79iOPVCbUlnNv0x7Cnvn3HiwUZuSNCLeRSnWJzwQDZG1BAUG0a9fw9p7D67qv9Pbi0ZBOpxa?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/nOjbyiHbDY5MhO9NkS27_xUUtHOzgUeJ_s3Ovh3KZXxaQqfyMJOJvHlXHgYwvbjhYOJc0qDD2pLijZImviQ6RgoDRy-FbKf9ufrbhDjQUXMRwp7adxvHhJ-3-ZxydwOALQkgAImrr5qIEJvNx8JA1Zwh0Qisg5C9Zh9O2vddqzx0PqSpYtxEu0S09chZHOxj?purpose=fullsize align="center")

Problems:

*   Deep nesting structure
    
*   Hard to maintain
    
*   Error handling scattered
    
*   Code readability collapses
    

This is where modern JavaScript evolved.

* * *

## Promises: Structured Async Handling

A Promise is an object that represents a future result.

It has three states:

*   Pending
    
*   Fulfilled
    
*   Rejected
    

* * *

### Promise Lifecycle

![Image](https://images.openai.com/static-rsc-4/d6S2vCV8jfF7kHg2bTL1RSzOowT_isKhB-ZlQQbknoSQK1qHlP60qW_Jc8GhBjuCouWKwHetv2aqDSEFiXIECAzvjqtafFyV8CB1gxrSxZHgXUy2rpZBlgtgefAoOTxprsfeuZyFkXoWiTlS7GZin0TjYLsEVEyoUh3j1pc3Zkqh5WC3dxSsvexd9J87Z0XE?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/nVduicbR9lwTXxe591mKkZ5PkDXFRPpfGuIXcIJlc88eH6HeTDUotMO_ew_9Rbl6WPa_BgScrFBsHLuv3JH6Wm665075TEtXz4TkcelXqdqsTLmOyPb3uzLpPRMCqygQpOVfcufr8g3ZCqyLpNBUeV9BkwsSS9-60kBfuAGC0hmiSZdapYQMDnGiHlPdF8Gp?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/uLHcDR-9kEye8noSJsw3PoOzceZgVaNEpjwW20-MK-2jZeT9GpXFHDJ_VpnlkMDSt0FhwY-1wuV_jGKQ3Wwp8RmruxW0zz8Y1igEwY54KtjHfoPwc2df0S8yI8L4WfZAYubjr_vmHgwNb2usyvrvDFu8pCTnZNZFiX4bBsmVuupdugKLgu-fS4HaUgJi8CLY?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/rr58o5lU-_3dHa6ZUhoE3-5h6mcGN96i_4J8zcOKpilqSCEDlLQLxZgUbmg79ZYCaoTzpC_9kRDq8DzCEo0edgQTkJAxMLk8YmGtHvXd-cAZk8C_Yhx2v1qZhOiwNrIX3jFFTGINp3rmWxCMx3TMognv2m9wugGy8486eaE8gmuVARR5tndb3BdCtfc1SNfF?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/q6VceFx-fCtDqFFKXJdtTajh03gVPbTF7bfcDRL1mtfmLCde2jgaTJsS0UXKzhyk1bNnOTd6sgUh1-uJmzI51llUJN9KiZPTw7v1-bfqel0JG8BnsFvZxiPINp3rp7qesazw-U0cU5jOPMlN3yBBbz4PnS02CDjyzsr-ujF-tpqzjrz2jYkn-v-eaZbmfQnv?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/AUrYp17NgmH2SwyQYR7u-Bt9ohhg2gmNK8DBkOR4UqZAUMpIGhXhBu_nf2XmKfG1I_cvQt4XW_sHjM5AlhlJQaD7It55vR5cQCrZhTHwW44zFmNfclPO8tQbsrFGFn1zGAVkfDv_zLF5zxLUIm_hHF02PFrY47U3LoxCpEkDfleDX8mloWwbz-iTkwLxMRcq?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/a3yzBSxVjsrXuFqT8OoChGpisCRArsWho5YnG40TNp4Y_8vj2zEuGCmWTcEXTkfE_u-Ww1NYRV9nwfTcq4_oWxpXQ_Xp19LBHoAof07MicWjbt2-aPpTDGJIQSWTKW5EciiUs6gNd_6_Xf0HMV4CCLhq9w43Mz7uOHbJXDHOgggLf9pLVRSrn47zBxBzVTK5?purpose=fullsize align="center")

* * *

## Promise-Based File Reading

```js
const fs = require('fs').promises;

fs.readFile('file.txt', 'utf-8')
    .then(data => {
        console.log(data);
    })
    .catch(err => {
        console.error(err);
    });

console.log("Next step");
```

* * *

## Solving Callback Hell with Promises

```js
const fs = require('fs').promises;

fs.readFile('file1.txt', 'utf-8')
    .then(data1 => {
        return fs.readFile('file2.txt', 'utf-8')
            .then(data2 => [data1, data2]);
    })
    .then(([data1, data2]) => {
        return fs.readFile('file3.txt', 'utf-8')
            .then(data3 => [data1, data2, data3]);
    })
    .then(([data1, data2, data3]) => {
        console.log(data1, data2, data3);
    })
    .catch(err => console.error(err));
```

Notice:

*   No pyramid structure
    
*   Flow is linear
    
*   Centralized error handling
    

* * *

## Callback vs Promise (Technical Comparison)

| Aspect | Callback | Promise |
| --- | --- | --- |
| Execution style | Nested | Chained |
| Error handling | Distributed | Centralized |
| Readability | Low | High |
| Debugging | Difficult | Easier |
| Composition | Weak | Strong (Promise chaining) |

* * *

## Internal Difference (Important for Interviews)

**Callback:**

*   Passed directly to async function
    
*   No control over execution timing
    
*   Can be called multiple times (risk)
    

**Promise:**

*   Guarantees single resolution
    
*   Immutable state
    
*   Supports chaining and composition
    

* * *

## Visual Comparison: Callback vs Promise Flow

![Image](https://images.openai.com/static-rsc-4/_E3ecHsvgWTvc_BeQYKCNIjtzI5JGX9hDi2uwcXLwGslFmIFU1OJ_67Gdb-EPiDyiaLC8KXurqhZPQ1n8GAoV4xPVhBYG46PEbMkyreBxLWB60YpSzpveZZXJLhng6Yo5MHKPKM_Js_KP7-ydpIs6ja7wQaSrfe3mwaj4TUqU7G5oaGPZamy93sRkE8PT50C?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/6xJEzufyIAnTI6FZr_FBGcFov00fRfBdZd5UosBBQcu0NJKbv_qUmsahVB9CtZRaVu2shIPEVl3mf50j2DTbU5a0CxeX2UzwCKINtunJk_mWmq12PTdCDjszofU_UhE_0p0wZdqd83dRfxPztPM9fGa5wBzG7xc7nO5TC7pjv7mesRp3XG0e0tEDRfPlQaWw?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/H4PjSRNUlbvL9iJrcyOvf-JoCH_QbjlTIPVrnlMBEs3OhbmOiNs5IKekPRBo8B5B_8mLSt3asF0QknWpNsA9LzWeT4_DyLC5-OGeXpzu0pSZfoWWkZGQcZG5neXUcoiXXQfVy44GWHFm-YENV46i-JSJ62oAxtzdyLJ92dtNmngACFlF5wK8iOTlYEcfAU10?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/XBeXJZO60UblL0mfFfydXabU1M2kbINX12o4mrGTqyVwp3EJtQYtdPohPG_RETjJDNf5JGxDy2My-KbmLWAw4gcuiRYfLYhr-BQcoI0lbG3mX1gsD6SzZf7nCwwqdyxlGA63ANr_FFVYuEhquzAR2LiayfGkxrcfP-Xenm5oNujPA1bdH_3qBYbngCg6tVHR?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/1DjCX22dhleRqfAvuNtks0w5Z3-u2lbiJ5SBt0v9YfufdQPZy6ANFbKW_OuX1BraNJiR6uDs8zzG7p8BNJ1bi5lNyjOfdbbke2J_NGa9IrnnTA7AwdQofrgzzTlBD3sHln-tObhTOHL-c3Pd1iK4s3qQXiQHa4BVWn17KY4IfvOhuWm7c5ogkvd3_oo2MGNx?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/o5AoJeDbKqiYkepWbwra0IX6tufcV1yGnxOxG1gsH3Yt-AiUcRBORgZGKYnUjJMOXuqSpg-YuuOFdEfuuWVPGvP1dbnosj2cSl92N0mBgAqHacAgqAWN1fBg1ChIikffuWaKes1wpHX7s_CXRRHxFswoBw3KB0nnwfhrojvYjGi71wVMRqQO9ZHbaOs1WmQM?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/mOdtgL16nkZxHiXHB4wSbINIRfQCaUZ8tUYTJsba3gecKg4H-8RqDMfSC6TI53ZxAPabfZnw24l8w_WmSgGaVcg3wNTWewDxe3lrOWKxkP7NvriBYSK0f7BqsvuxENuPc9kT9evX9vHkXROrKL4ptbYJNa54_7unpF2LvkcJyMCdt79Urdntuy_-EHtIFATj?purpose=fullsize align="center")

* * *

## Advanced Insight: Microtask Queue vs Callback Queue

This is where most candidates fail in interviews.

Node.js has:

*   Callback Queue (macrotasks)
    
*   Microtask Queue (Promises)
    

Priority:

1.  Current execution
    
2.  Microtasks (Promises)
    
3.  Macrotasks (Callbacks)
    

* * *

### Execution Order Example

```js
console.log("Start");

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

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

console.log("End");
```

Output:

```plaintext
Start
End
Promise
Callback
```

* * *

### Microtask vs Macrotask Visualization

![Image](https://images.openai.com/static-rsc-4/5_5jt0vo-R01GtgacrgJ7m_1BsbECwS86T9WaPI95_DmDUuXdHxpG3iDajwbxX9Mzr0ZyhtMbMIJRBJDNR6vqCo867Lws7fFc51r6Q6uE0lw6YAdMgXsi7wuvetzDwDVIJNUgG9qduj0di2D81wdNy8J2Toxc09kWwO3cKGIqmtFe4dPF-ypxO_8mnHQZK0O?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/acj39yi708Zay_27EJnqm5max7krg8DCXCrT2lnchn1rxDHmRAEup84AeKXuUXFkjjdR05LaRupkvbL-kXzf-kqxMyppfLvAuEP9IEI_v_UZDR1a0bqSU5_R4pgWzgfyXDpKSRUnwZgntHsqqNtQXrmxUWrfqrLgW9_jkckV8PNgRIiaVi18F8Ox9WFnA-tQ?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/nqciHvMQLjICcB_FN4FdBqiOjge53FidQbOXBzQjA0b-GcT5HUBapMCTxJj8x43P6jMmLNTqsiV_QK1tnVL3Yko2zlUyBuyuJ3sHnt-BtMx2qgfcpyfLyZ5v_CrReUu-LC9xcv07TBtlq0CdOUbEvKRLTm8I3yDp0heoFWxrsk1RzQOASIRpgoBISQrtdvPh?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/_KNdjQjvh_KYm37dFeJk1O0Kv1sarrysk8bvDKBJwXZB1cdbK0XkRByDGSKqvZTli7zLREM9p2xDs5YrzE6be_dXjkao4gtA-YITSmC_bh2YrFcW2FPX9nUxs1wIeDQq1yLYzuPGeMaWahn0dR4LEsNDYcvrbPzX0fTeBvMvx11qE0OrA4RJq9Iat9GBa9Oo?purpose=fullsize align="center")

![Image](https://images.openai.com/static-rsc-4/xj3Nsa5xmT-JYZM5KwvG3mbl5_sqj-IvLyASwNLlvzYQsbn0XHS-PiKcbMwpmrUyduL8a_zRW-7-AU1G8tYSyuc45kYwyHaXSKFicEKZHu_mvVy56WqyL3-y1b57ICsCekvJZdodQ59p2l7EwG5CBJPPnnAAjMB150HNWWtu1RmJgU_BQcOylofucOg6Ag76?purpose=fullsize align="center")

* * *

## Final Step: async/await (Modern Standard)

Promises become even cleaner with async/await.

```js
const fs = require('fs').promises;

async function readFiles() {
    try {
        const data1 = await fs.readFile('file1.txt', 'utf-8');
        const data2 = await fs.readFile('file2.txt', 'utf-8');
        const data3 = await fs.readFile('file3.txt', 'utf-8');

        console.log(data1, data2, data3);
    } catch (err) {
        console.error(err);
    }
}
```

This looks synchronous, but it is fully asynchronous under the hood.

* * *

## Key Takeaways

*   Node.js uses async code to avoid blocking the event loop
    
*   Callbacks are the foundation but lead to complexity
    
*   Promises provide structure and reliability
    
*   Microtasks (Promises) execute before callbacks
    
*   async/await is built on top of Promises and is the current standard
