iT邦幫忙

2024 iThome 鐵人賽

DAY 19
1
JavaScript

我推的TypeScript 操作大全系列 第 19

我推Day19 - 學會 TypeScript 的 using,讓程式碼優雅無壓力

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20241003/20124462gl3CFuPcXK.jpg


using 關鍵字簡化你的 TypeScript 程式碼

在寫程式的過程中,除了記憶體之外,我們有時需要使用一些外部資源,比如資料庫連線、檔案操作、網路請求等。
這些資源不像記憶體那樣能自動釋放,需要我們在程式使用完後手動關閉或釋放。

如果我們不小心忘記釋放這些資源,可能會導致系統資源被佔用過多,甚至出現應用程式崩潰等問題。

但別擔心,TypeScript 最新推出的 using 關鍵字正是為了解決這類資源管理的問題!

透過 using,我們可以讓程式在使用完某個資源後自動釋放它,而不需要我們手動去關閉或釋放。
這樣,我們就能更優雅地管理資源,減少因為忘記釋放資源而導致的錯誤,讓程式碼更穩健且無壓力!💻✨

今天的主角就是「using」這個超實用的關鍵字,能讓物件在用完後自動清理自己!
是不是覺得很神奇?

其實這個概念來自 C#,但 TypeScript 可不是在單純模仿,而是選取了 C# 中最棒的功能,專門提升開發者的使用體驗!🎉

接下來,我會為大家詳細說明 using 的運作方式,以及它最適合應用的場景。
準備好了嗎?讓我們一起 dive in 吧!🚀


了解 TypeScript 中的 "using" 關鍵字

在 TypeScript 5.2 版本中,新增了一個非常實用的關鍵字 using,這個關鍵字讓開發者可以更優雅地管理程式中的資源,特別是那些需要在使用後釋放的資源。

using 是什麼?

using 關鍵字允許開發者定義一個可被自動釋放的物件,這些物件稱為「資源」(resources)。
這些資源通常是資料庫連線、檔案操作等,當它們不再被使用時,程式會自動釋放它們,避免出現資源耗盡或記憶體洩漏等問題。

這個概念來自於 C# 語言,在 C# 中,using 主要用來確保物件在使用完後自動執行清理操作。
而 TypeScript 引入這個功能,透過 Symbol.disposeSymbol.asyncDispose 來標記物件為可釋放的資源,並自動處理它們的釋放。


using 的主要功能

  1. 定義資源:用 using 關鍵字定義一個需要自動釋放的資源。
  2. 自動釋放:當程式執行完該資源的相關操作後,using 會自動釋放該資源,而無需手動關閉或釋放。
  3. Symbol.dispose:這是一個特殊的函式,用來標記某個物件為可釋放的資源。
  4. using 被應用時,該資源會在不需要時自動執行 dispose 函式來清理資源。

using 如何使用?

  • using 是如何運作的?

using 關鍵字的使用方式跟 constlet 很相似。

// 注意:必須指定某個值或函式回傳的值。
using x = getX();

雖然這樣的賦值是可以的,但 using 應該只用於以下兩種情況:

  1. 使用 Symbol.dispose 關鍵字的物件。
  2. 回傳含有 Symbol.dispose 關鍵字的函式。

其他情況請繼續使用 constletSymbol.dispose 是 TypeScript 中的一個特殊函式,用來標記物件為「資源」——也就是一個可被釋放的物件。

我們可以將 using 關鍵字用在類似 constlet 的地方,但前提是它要被分配給一個包含 Symbol.disposeSymbol.asyncDispose 的物件。

// 使用 Symbol.dispose 標記的可釋放物件
const disposableObject = {
  [Symbol.dispose]: () => {
    console.log("Dispose of me!"); // 當物件不再使用時會被清理
  },
};

// 使用 using 關鍵字來管理物件資源
using resource = disposableObject;

在這段程式碼中,我們定義了一個含有 Symbol.dispose 的物件 disposableObject。當程式不再需要這個物件時,using 會自動執行 dispose 函式,並釋放資源,顯示「Dispose of me!」。


await using:異步釋放資源

在某些情況下,釋放資源可能需要進行異步操作。這時,我們可以使用 await using 來處理,並搭配 Symbol.asyncDispose 進行異步釋放資源。

const getResource = () => ({
  [Symbol.asyncDispose]: async () => {
    await someAsyncFunc(); // 進行某些異步操作後釋放資源
  },
});

{
  await using resource = getResource();
}

透過 await using,我們可以確保在資源釋放前,所有異步操作都已完成。

總結來說,using 是 TypeScript 中的一個強大工具,能夠幫助我們更輕鬆地管理程式中的資源,特別是那些需要在使用完後釋放的資源。
透過 using,我們不再需要手動管理資源的釋放,從而減少錯誤並提升程式碼的可維護性。


常見應用場景 1 :資料庫連線

資料庫連線是 using 最常見的應用場景之一。
為什麼呢?很簡單,因為你不需要在程式碼中手動關閉資料庫連線,Symbol.asyncDispose 函式會自動幫你處理!
這樣可以大幅減少潛在的錯誤和後續問題。

Symbol.disposeSymbol.asyncDispose 是 TypeScript 提供的特殊符號,用來標記物件在完成操作後應自動進行清理。
Symbol.dispose 用於同步資源的釋放,而 Symbol.asyncDispose 則讓我們能夠在釋放資源時進行異步操作,確保所有背景作業都已完成後再釋放資源。

讓我們來看兩個程式碼範例,分別展示如何使用 using 與不用 using 來管理資料庫連線。

不使用 using 的程式碼

const connection = await getDb();

try {
  // 用 connection 做一些事情
} finally {
  await connection.close(); // 最後手動關閉連線
}

使用 using 的程式碼

const getConnection = async () => {
  const connection = await getDb();

  return {
    connection,
    [Symbol.asyncDispose]: async () => {
      await connection.close(); // 自動關閉連線
    },
  };
};

{
  await using db = await getConnection();

  // 用 db.connection 做一些事情

} // 自動關閉資料庫連線!

有了 usingSymbol.asyncDispose,資料庫連線的關閉現在可以自動負責!
讓你可以更安心地管理資源,減少程式碼中的潛在漏洞。


常見應用場景 2:檔案操作

不使用 using 的程式碼

在這個範例中,我們手動開啟和關閉檔案。需要小心不要忘記關閉檔案,否則會導致資源洩漏。

import { promises as fs } from 'fs';

async function readFileWithoutUsing(filePath: string) {
  const fileHandle = await fs.open(filePath, 'r');
  try {
    const content = await fileHandle.readFile('utf8');
    console.log(content);
  } finally {
    // 手動關閉檔案,避免資源洩漏
    await fileHandle.close();
  }
}

readFileWithoutUsing('example.txt');
  • 問題:
    在這裡,我們必須確保無論程式碼運行的過程中發生什麼情況(如異常),都能手動關閉檔案。
    如果忘記 finally 區塊中的 close 呼叫,檔案將一直保持打開狀態,導致資源無法釋放。

使用 using 的程式碼

透過 using,我們可以讓 TypeScript 自動處理檔案的關閉過程,無需手動處理資源的釋放。

import { promises as fs } from 'fs';

async function getFileResource(filePath: string) {
  const fileHandle = await fs.open(filePath, 'r');
  return {
    fileHandle,
    [Symbol.asyncDispose]: async () => {
      // 當資源釋放時自動關閉檔案
      await fileHandle.close();
    }
  };
}

async function readFileWithUsing(filePath: string) {
  await using resource = await getFileResource(filePath);
  const content = await resource.fileHandle.readFile('utf8');
  console.log(content);
}

readFileWithUsing('example.txt');

使用 using 時,TypeScript 會自動釋放資源,無需顯式地在 finally 區塊中關閉檔案。
這樣可以減少忘記釋放資源的風險,程式碼也更加乾淨。


總結要點:精通 TypeScript using 關鍵字的妙用

  • using 用來定義和管理可釋放的資源。
  • Symbol.disposeSymbol.asyncDispose 分別處理同步和異步的資源釋放。
  • 在常見的應用場景中,像資料庫連線、檔案操作等,using 可以幫助自動管理資源,減少錯誤發生

每一次優化程式碼,都是邁向高效開發的進步!
相信自己,讓 using 幫助你輕鬆寫出更穩健的程式碼!(≧▽≦)🚀


上一篇
我推Day18 - TypeScript 超能力解鎖:物件導向與模組的完美結合
下一篇
我推Day20 - 從零開始:搞懂 TypeScript 運算子的奧義
系列文
我推的TypeScript 操作大全30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言