O'zbek

JavaScript'ning `using` va `await using` yordamida yangi Aniq Resurslarni Boshqarish tizimini o'zlashtiring. Tozalashni avtomatlashtirish, resurs sizib chiqishini oldini olish va toza, ishonchli kod yozishni o'rganing.

JavaScript'ning Yangi Superkuchi: Aniq Resurslarni Boshqarishga Chuqur Kirish

Dasturiy ta'minotni ishlab chiqishning dinamik dunyosida resurslarni samarali boshqarish mustahkam, ishonchli va unumdor ilovalarni yaratishning asosidir. O'nlab yillar davomida JavaScript dasturchilari fayl dastaklari, tarmoq ulanishlari yoki ma'lumotlar bazasi sessiyalari kabi muhim resurslarning to'g'ri bo'shatilishini ta'minlash uchun try...catch...finally kabi qo'lda boshqariladigan uslublarga tayanganlar. Funktsional bo'lishiga qaramay, bu yondashuv ko'pincha keraksiz so'zlar bilan to'la, xatoliklarga moyil va tezda boshqarib bo'lmaydigan holga kelishi mumkin, bu uslub ba'zan murakkab stsenariylarda "halokat piramidasi" deb ataladi.

Til uchun paradigma o'zgarishiga xush kelibsiz: Aniq Resurslarni Boshqarish (ERM). ECMAScript 2024 (ES2024) standartida yakunlangan, C#, Python va Java kabi tillardagi o'xshash tuzilmalardan ilhomlangan ushbu kuchli xususiyat resurslarni tozalashni boshqarishning deklarativ va avtomatlashtirilgan usulini taqdim etadi. Yangi using va await using kalit so'zlaridan foydalangan holda, JavaScript endi dasturlashning abadiy muammosiga ancha nafis va xavfsizroq yechim taklif qiladi.

Ushbu keng qamrovli qo'llanma sizni JavaScript'ning Aniq Resurslarni Boshqarish tizimi bo'ylab sayohatga olib chiqadi. Biz u hal qiladigan muammolarni o'rganamiz, uning asosiy tushunchalarini tahlil qilamiz, amaliy misollarni ko'rib chiqamiz va dunyoning qayerida dastur yaratayotganingizdan qat'i nazar, toza va chidamliroq kod yozish imkonini beradigan ilg'or uslublarni ochib beramiz.

Eski Usul: Resurslarni Qo'lda Tozalash Muammolari

Yangi tizimning nafisligini qadrlashdan oldin, avvalo, eskisining og'riqli nuqtalarini tushunishimiz kerak. JavaScript'da resurslarni boshqarishning klassik uslubi bu try...finally blokidir.

Mantiq oddiy: siz try blokida resursni olasiz va uni finally blokida bo'shatasiz. finally bloki try blokidagi kod muvaffaqiyatli bajariladimi, xatolik beradimi yoki muddatidan oldin qaytadimi, qat'i nazar, bajarilishini kafolatlaydi.

Keling, server tomonidagi keng tarqalgan stsenariyni ko'rib chiqaylik: faylni ochish, unga ma'lumot yozish va keyin faylning yopilishini ta'minlash.

Misol: try...finally yordamida oddiy fayl amali


const fs = require('fs/promises');

async function processFile(filePath, data) {
  let fileHandle;
  try {
    console.log('Opening file...');
    fileHandle = await fs.open(filePath, 'w');
    console.log('Writing to file...');
    await fileHandle.write(data);
    console.log('Data written successfully.');
  } catch (error) {
    console.error('An error occurred during file processing:', error);
  } finally {
    if (fileHandle) {
      console.log('Closing file...');
      await fileHandle.close();
    }
  }
}

Bu kod ishlaydi, lekin u bir nechta zaifliklarni ochib beradi:

Endi, ma'lumotlar bazasi ulanishi va fayl dastagi kabi bir nechta resursni boshqarishni tasavvur qiling. Kod tezda ichma-ich joylashgan tartibsizlikka aylanadi:


async function logQueryResultToFile(query, filePath) {
  let dbConnection;
  try {
    dbConnection = await getDbConnection();
    const result = await dbConnection.query(query);

    let fileHandle;
    try {
      fileHandle = await fs.open(filePath, 'w');
      await fileHandle.write(JSON.stringify(result));
    } finally {
      if (fileHandle) {
        await fileHandle.close();
      }
    }
  } finally {
    if (dbConnection) {
      await dbConnection.release();
    }
  }
}

Bu ichma-ich joylashuvni qo'llab-quvvatlash va kengaytirish qiyin. Bu yaxshiroq abstraksiya kerakligining aniq belgisidir. Aniq Resurslarni Boshqarish aynan shu muammoni hal qilish uchun ishlab chiqilgan.

Paradigma O'zgarishi: Aniq Resurslarni Boshqarish Tamoyillari

Aniq Resurslarni Boshqarish (ERM) resurs obyekti va JavaScript ish vaqti o'rtasida shartnoma o'rnatadi. Asosiy g'oya oddiy: obyekt o'zini qanday tozalash kerakligini e'lon qilishi mumkin, va til obyekt ko'rinish doirasidan chiqqanda ushbu tozalashni avtomatik ravishda bajarish uchun sintaksisni taqdim etadi.

Bunga ikkita asosiy komponent orqali erishiladi:

  1. "Disposable" Protokoli: Obyektlar uchun maxsus belgilar yordamida o'zlarining tozalash mantiqini aniqlashning standart usuli: sinxron tozalash uchun Symbol.dispose va asinxron tozalash uchun Symbol.asyncDispose.
  2. using va await using E'lonlari: Resursni blok ko'rinish doirasiga bog'laydigan yangi kalit so'zlar. Blokdan chiqilganda, resursning tozalash metodi avtomatik ravishda chaqiriladi.

Asosiy Tushunchalar: `Symbol.dispose` va `Symbol.asyncDispose`

ERM markazida ikkita yangi taniqli Symbol (belgi) mavjud. Kaliti ushbu belgilardan biri bo'lgan metodga ega bo'lgan obyekt "yo'q qilinadigan resurs" (disposable resource) hisoblanadi.

Symbol.dispose yordamida Sinxron Tozalash

Symbol.dispose belgisi sinxron tozalash metodini belgilaydi. Bu, fayl dastagini sinxron yopish yoki xotiradagi qulfni bo'shatish kabi, tozalash hech qanday asinxron operatsiyalarni talab qilmaydigan resurslar uchun mos keladi.

Keling, o'zini o'zi tozalaydigan vaqtinchalik fayl uchun o'ram (wrapper) yaratamiz.


const fs = require('fs');
const path = require('path');

class TempFile {
  constructor(content) {
    this.path = path.join(__dirname, `temp_${Date.now()}.txt`);
    fs.writeFileSync(this.path, content);
    console.log(`Created temp file: ${this.path}`);
  }

  // Bu sinxron yo'q qilinadigan metod
  [Symbol.dispose]() {
    console.log(`Disposing temp file: ${this.path}`);
    try {
      fs.unlinkSync(this.path);
      console.log('File deleted successfully.');
    } catch (error) {
      console.error(`Failed to delete file: ${this.path}`, error);
      // dispose ichidagi xatoliklarni ham qayta ishlash muhim!
    }
  }
}

Endi `TempFile` ning har qanday nusxasi yo'q qilinadigan resursdir. Uning Symbol.dispose bilan kalitlangan metodi faylni diskdan o'chirish mantiqini o'z ichiga oladi.

Symbol.asyncDispose yordamida Asinxron Tozalash

Ko'pgina zamonaviy tozalash operatsiyalari asinxrondir. Ma'lumotlar bazasi ulanishini yopish tarmoq orqali `QUIT` buyrug'ini yuborishni o'z ichiga olishi mumkin, yoki xabarlar navbati mijozi o'zining chiquvchi buferini bo'shatishi kerak bo'lishi mumkin. Bunday stsenariylar uchun biz Symbol.asyncDispose dan foydalanamiz.

Symbol.asyncDispose bilan bog'liq bo'lgan metod `Promise` qaytarishi (yoki `async` funksiya bo'lishi) kerak.

Keling, pulga (pool) asinxron ravishda qaytarilishi kerak bo'lgan soxta ma'lumotlar bazasi ulanishini modellashtiramiz.


// Soxta ma'lumotlar bazasi puli
const mockDbPool = {
  getConnection: () => {
    console.log('DB connection acquired.');
    return new MockDbConnection();
  }
};

class MockDbConnection {
  query(sql) {
    console.log(`Executing query: ${sql}`);
    return Promise.resolve({ success: true, rows: [] });
  }

  // Bu asinxron yo'q qilinadigan metod
  async [Symbol.asyncDispose]() {
    console.log('Releasing DB connection back to the pool...');
    // Ulanishni bo'shatish uchun tarmoq kechikishini simulyatsiya qilish
    await new Promise(resolve => setTimeout(resolve, 50));
    console.log('DB connection released.');
  }
}

Endi har qanday `MockDbConnection` nusxasi asinxron yo'q qilinadigan resurs hisoblanadi. U endi kerak bo'lmaganda o'zini asinxron ravishda qanday bo'shatishni biladi.

Yangi Sintaksis: `using` va `await using` Amalda

Yo'q qilinadigan (disposable) sinflarimiz aniqlanganidan so'ng, ularni avtomatik ravishda boshqarish uchun yangi kalit so'zlardan foydalanishimiz mumkin. Bu kalit so'zlar xuddi `let` va `const` kabi blok doirasidagi e'lonlarni yaratadi.

using yordamida Sinxron Tozalash

using kalit so'zi Symbol.dispose ni amalga oshiradigan resurslar uchun ishlatiladi. Kod ijrosi using e'loni qilingan blokdan chiqqanda, [Symbol.dispose]() metodi avtomatik ravishda chaqiriladi.

Keling, `TempFile` sinfimizdan foydalanamiz:


function processDataWithTempFile() {
  console.log('Entering block...');
  using tempFile = new TempFile('This is some important data.');

  // Bu yerda tempFile bilan ishlashingiz mumkin
  const content = fs.readFileSync(tempFile.path, 'utf8');
  console.log(`Read from temp file: "${content}"`);

  // Bu yerda tozalash kodi kerak emas!
  console.log('...doing more work...');
} // <-- tempFile.[Symbol.dispose]() aynan shu yerda avtomatik ravishda chaqiriladi!

processDataWithTempFile();
console.log('Block has been exited.');

Natija quyidagicha bo'ladi:

Entering block...
Created temp file: /path/to/temp_1678886400000.txt
Read from temp file: "This is some important data."
...doing more work...
Disposing temp file: /path/to/temp_1678886400000.txt
File deleted successfully.
Block has been exited.

Qanchalik toza ekanligiga qarang! Resursning butun hayot sikli blok ichida joylashgan. Biz uni e'lon qilamiz, ishlatamiz va unutamiz. Til tozalashni o'z zimmasiga oladi. Bu o'qiluvchanlik va xavfsizlikda juda katta yaxshilanishdir.

Bir nechta Resursni Boshqarish

Siz bitta blokda bir nechta using e'loniga ega bo'lishingiz mumkin. Ular yaratilishining teskari tartibida yo'q qilinadi (LIFO yoki "stek" kabi xatti-harakat).


{
  using resourceA = new MyDisposable('A'); // Birinchi yaratildi
  using resourceB = new MyDisposable('B'); // Ikkinchi yaratildi
  console.log('Inside block, using resources...');
} // avval resourceB, keyin resourceA yo'q qilinadi

await using yordamida Asinxron Tozalash

await using kalit so'zi usingning asinxron muqobilidir. U Symbol.asyncDispose ni amalga oshiradigan resurslar uchun ishlatiladi. Tozalash asinxron bo'lganligi sababli, bu kalit so'z faqat `async` funksiya ichida yoki modulning yuqori darajasida (agar yuqori darajadagi await qo'llab-quvvatlansa) ishlatilishi mumkin.

Keling, `MockDbConnection` sinfimizdan foydalanamiz:


async function performDatabaseOperation() {
  console.log('Entering async function...');
  await using db = mockDbPool.getConnection();

  await db.query('SELECT * FROM users');

  console.log('Database operation complete.');
} // <-- await db.[Symbol.asyncDispose]() shu yerda avtomatik chaqiriladi!

(async () => {
  await performDatabaseOperation();
  console.log('Async function has completed.');
})();

Natija asinxron tozalashni namoyish etadi:

Entering async function...
DB connection acquired.
Executing query: SELECT * FROM users
Database operation complete.
Releasing DB connection back to the pool...
(waits 50ms)
DB connection released.
Async function has completed.

Xuddi using kabi, await using sintaksisi butun hayot siklini boshqaradi, lekin u asinxron tozalash jarayonini to'g'ri `awaits` qiladi. U hatto faqat sinxron yo'q qilinadigan resurslarni ham boshqara oladi — u shunchaki ularni kutmaydi.

Ilg'or Uslublar: `DisposableStack` va `AsyncDisposableStack`

Ba'zida usingning oddiy blok ko'rinish doirasi yetarlicha moslashuvchan bo'lmaydi. Agar hayot sikli bitta leksik blokka bog'lanmagan resurslar guruhini boshqarish kerak bo'lsa-chi? Yoki Symbol.dispose ga ega obyektlarni yaratmaydigan eski kutubxona bilan integratsiya qilayotgan bo'lsangiz-chi?

Bunday stsenariylar uchun JavaScript ikkita yordamchi sinfni taqdim etadi: `DisposableStack` va `AsyncDisposableStack`.

`DisposableStack`: Moslashuvchan Tozalash Menejeri

`DisposableStack` - bu tozalash operatsiyalari to'plamini boshqaradigan obyekt. Uning o'zi ham yo'q qilinadigan resursdir, shuning uchun uning butun hayot siklini using bloki bilan boshqarishingiz mumkin.

Uning bir nechta foydali metodlari mavjud:

Misol: Shartli Resurslarni Boshqarish

Faqat ma'lum bir shart bajarilganda log faylini ochadigan, lekin barcha tozalash ishlari oxirida bir joyda bajarilishini xohlaydigan funksiyani tasavvur qiling.


function processWithConditionalLogging(shouldLog) {
  using stack = new DisposableStack();

  const db = stack.use(getDbConnection()); // Har doim MB dan foydalaning

  if (shouldLog) {
    const logFileStream = fs.createWriteStream('app.log');
    // Oqim uchun tozalashni kechiktiring
    stack.defer(() => {
      console.log('Closing log file stream...');
      logFileStream.end();
    });
    db.logTo(logFileStream);
  }

  db.doWork();

} // <-- Stek yo'q qilinadi va barcha ro'yxatdan o'tgan tozalash funksiyalari LIFO tartibida chaqiriladi.

`AsyncDisposableStack`: Asinxron Dunyo Uchun

Taxmin qilganingizdek, `AsyncDisposableStack` asinxron versiyadir. U ham sinxron, ham asinxron yo'q qilinadigan resurslarni boshqara oladi. Uning asosiy tozalash metodi `.disposeAsync()` bo'lib, u barcha asinxron tozalash operatsiyalari yakunlanganda bajariladigan `Promise` qaytaradi.

Misol: Aralash Resurslarni Boshqarish

Keling, ma'lumotlar bazasi ulanishi (asinxron tozalash) va vaqtinchalik fayl (sinxron tozalash) kerak bo'lgan veb-server so'rovlarini qayta ishlovchisini yaratamiz.


async function handleRequest() {
  await using stack = new AsyncDisposableStack();

  // Asinxron yo'q qilinadigan resursni boshqarish
  const dbConnection = await stack.use(getAsyncDbConnection());

  // Sinxron yo'q qilinadigan resursni boshqarish
  const tempFile = stack.use(new TempFile('request data'));

  // Eski API'dan resursni qabul qilish
  const legacyResource = getLegacyResource();
  stack.adopt(legacyResource, () => legacyResource.shutdown());

  console.log('Processing request...');
  await doWork(dbConnection, tempFile.path);

} // <-- stack.disposeAsync() chaqiriladi. U asinxron tozalashni to'g'ri kutadi.

`AsyncDisposableStack` murakkab sozlash va tozalash mantiqini toza, bashorat qilinadigan tarzda boshqarish uchun kuchli vositadir.

`SuppressedError` yordamida Mustahkam Xatoliklarni Qayta Ishlash

ERMning eng nozik, ammo muhim yaxshilanishlaridan biri bu uning xatoliklarni qanday qayta ishlashidir. Agar using bloki ichida xato yuz bersa va keyingi avtomatik tozalash paytida *yana bir* xato yuz bersa nima bo'ladi?

Eski try...finally dunyosida, finally blokidagi xato odatda try blokidagi asl, muhimroq xatoni bekor qiladi yoki "bostiradi". Bu ko'pincha nosozliklarni tuzatishni juda qiyinlashtirardi.

ERM buni yangi global xato turi bilan hal qiladi: `SuppressedError`. Agar boshqa xato allaqachon tarqalayotgan paytda tozalash jarayonida xato yuz bersa, tozalash xatosi "bostiriladi". Asl xato yuzaga chiqariladi, lekin endi uning `suppressed` xususiyati tozalash xatosini o'z ichiga oladi.


class FaultyResource {
  [Symbol.dispose]() {
    throw new Error('Error during disposal!');
  }
}

try {
  using resource = new FaultyResource();
  throw new Error('Error during operation!');
} catch (e) {
  console.log(`Caught error: ${e.message}`); // Operatsiya paytida xato!
  if (e.suppressed) {
    console.log(`Suppressed error: ${e.suppressed.message}`); // Tozalash paytida xato!
    console.log(e instanceof SuppressedError); // false
    console.log(e.suppressed instanceof Error); // true
  }
}

Bu xatti-harakat asl nosozlik kontekstini hech qachon yo'qotmasligingizni ta'minlaydi, bu esa ancha mustahkam va sozlanishi oson tizimlarga olib keladi.

JavaScript Ekosistemasi bo'ylab Amaliy Qo'llash Holatlari

Aniq Resurslarni Boshqarishning qo'llanilish sohalari keng va butun dunyodagi dasturchilar uchun, ular back-end, front-end yoki testlash sohasida ishlayotganlaridan qat'i nazar, dolzarbdir.

Brauzer va Ish Vaqti Qo'llab-quvvatlashi

Zamonaviy xususiyat sifatida, Aniq Resurslarni Boshqarishni qayerda ishlatishingiz mumkinligini bilish muhimdir. 2023-yil oxiri / 2024-yil boshiga kelib, asosiy JavaScript muhitlarining so'nggi versiyalarida qo'llab-quvvatlash keng tarqalgan:

Eskiroq muhitlar uchun siz using sintaksisini o'zgartirish va kerakli belgilar hamda stek sinflarini polifill qilish uchun tegishli plaginlar bilan Babel kabi transpylerlarga tayanishishingiz kerak bo'ladi.

Xulosa: Xavfsizlik va Aniqravshanlikning Yangi Davri

JavaScript'ning Aniq Resurslarni Boshqarish tizimi shunchaki sintaktik qulaylik emas; bu xavfsizlik, aniqlik va qo'llab-quvvatlanuvchanlikni rag'batlantiradigan tilning fundamental takomillashuvidir. Resurslarni tozalashning zerikarli va xatoliklarga moyil jarayonini avtomatlashtirish orqali, u dasturchilarga o'zlarining asosiy biznes mantiqiga e'tibor qaratish imkonini beradi.

Asosiy xulosalar:

Yangi loyihalarni boshlayotganingizda yoki mavjud kodni refaktoring qilayotganingizda, ushbu kuchli yangi uslubni qo'llashni o'ylab ko'ring. Bu sizning JavaScript kodingizni toza, ilovalaringizni ishonchliroq qiladi va dasturchi sifatidagi hayotingizni biroz osonlashtiradi. Bu zamonaviy, professional JavaScript yozish uchun haqiqiy global standartdir.