فهرست سرفصل‌های TypeScript
خانه (Home) معرفی (Introduction) شروع سریع (Get Started) انواع ساده (Simple Types) تعریف صریح و استنتاج نوع (Explicit & Inference) انواع ویژه (Special Types) آرایه ها (Arrays) تاپل ها (Tuples) انواع شیء (Object Types) شمارشی ها (Enums) نام مستعار و اینترفیس ها (Aliases & Interfaces) انواع اتحادی (Union Types) توابع (Functions) تبدیل نوع (Casting) کلاس ها (Classes) جنریک های پایه (Basic Generics) انواع کاربردی (Utility Types) کلیدواژه keyof (Keyof) Null (Null) Definitely Typed (Definitely Typed) به روزرسانی های نسخه 5 (5 Updates) پیکربندی (Configuration) با Node.js (with Node.js) با React (with React) ابزارها (Tooling) انواع پیشرفته (Advanced Types) نگهبان های نوع (Type Guards) انواع شرطی (Conditional Types) انواع نگاشتی (Mapped Types) استنتاج نوع (Type Inference) انواع لیترال (Literal Types) فضای نام (Namespaces) امضاهای ایندکس (Index Signatures) ادغام اعلان ها (Declaration Merging) برنامه نویسی ناهمگام (Async Programming) دکوراتورها (Decorators) در پروژه های JS (in JS Projects) مهاجرت (Migration) مدیریت خطا (Error Handling) بهترین شیوه ها (Best Practices) ادیتور (Editor) تمرین ها (Exercises) آزمون (Quiz) سرفصل دوره (Syllabus) برنامه مطالعه (Study Plan) گواهینامه (Certificate)
نتیجه‌ای برای جستجو یافت نشد.
TypeScript

TypeScript — برنامه نویسی ناهمگام (Async Programming)

آخرین بروزرسانی: 1404/08/14

برنامه نویسی ناهمگام (Async Programming)

برنامه نویسی ناهمگام یعنی کارها همزمان جلو بروند. بنابراین رابط کاربری قفل نمی شود. اینجا با تایپ اسکریپت، همه چیز تایپ دار و مطمئن می شود.

وعده ها (Promises) در تایپ اسکریپت

«وعده (Promise)» یعنی قول یک نتیجه آینده. جنس نتیجه را با Promise<T> مشخص می کنیم.

const fetchGreeting = (): Promise<string> => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const success = Math.random() > 0.5;
      if (success) {
        resolve('Hello, TypeScript!');
      } else {
        reject(new Error('Failed to fetch greeting'));
      }
    }, 1000);
  });
};

fetchGreeting()
  .then((greeting: string) => {
    console.log(greeting.toUpperCase());
  })
  .catch((error: Error) => {
    console.error('Error:', error.message);
  });

مشاهده در ادیتور

async/await با تایپ اسکریپت

«async/await» نوشتن کد ناهمگام را ساده می کند. مانند خواندن کد عادی است.

interface User {
  id: number;
  name: string;
  email: string;
  role: 'admin' | 'user' | 'guest';
}

async function fetchUsers(): Promise<User[]> {
  console.log('Fetching users...');
  await new Promise((resolve) => setTimeout(resolve, 1000));
  return [
    { id: 1, name: 'Alice', email: 'alice@example.com', role: 'admin' },
    { id: 2, name: 'Bob', email: 'bob@example.com', role: 'user' }
  ];
}

async function processUsers(): Promise<User[]> {
  try {
    const users = await fetchUsers();
    console.log('Fetched ' + users.length + ' users');
    const adminEmails = users
      .filter((u) => u.role === 'admin')
      .map((u) => u.email);
    console.log('Admin emails:', adminEmails);
    return users;
  } catch (error) {
    console.error('Failed to process users:', (error as Error).message);
    throw error;
  }
}

processUsers()
  .then(() => console.log('Processing complete'))
  .catch((err) => console.error('Processing failed:', err));

مشاهده در ادیتور

نکته: همه توابع async یک Promise برمی گردانند. بنابراین نتیجه همیشه Promise است.

Promise.all برای اجرای موازی

چند کار را باهم شروع کن. سپس همه با هم تمام شوند.

interface Product {
  id: number;
  name: string;
  price: number;
}

async function fetchProduct(id: number): Promise<Product> {
  await new Promise((resolve) => setTimeout(resolve, Math.random() * 1000));
  return { id: id, name: 'Product ' + id, price: Math.floor(Math.random() * 100) };
}

async function fetchMultipleProducts(): Promise<void> {
  try {
    const [p1, p2, p3] = await Promise.all([
      fetchProduct(1),
      fetchProduct(2),
      fetchProduct(3)
    ]);
    const total = [p1, p2, p3].reduce((sum, p) => sum + p.price, 0);
    console.log('Total price: $' + total.toFixed(2));
  } catch (error) {
    console.error('Error fetching products:', error);
  }
}

fetchMultipleProducts();

مشاهده در ادیتور

Promise.race برای زمان سنج

با «race» اولین نتیجه مهم است. برای تایم اوت عالی است.

const timeout = (ms: number): Promise<never> => {
  return new Promise((_, reject) => {
    setTimeout(() => reject(new Error('Timeout after ' + ms + 'ms')), ms);
  });
};

async function fetchWithTimeout<T>(promise: Promise<T>, timeoutMs: number): Promise<T> {
  return Promise.race([
    promise,
    timeout(timeoutMs).then(() => {
      throw new Error('Request timed out after ' + timeoutMs + 'ms');
    })
  ]);
}

مشاهده در ادیتور

Promise.allSettled برای گزارش کامل

می خواهی همه تمام شوند. چه موفق، چه ناموفق. از «allSettled» استفاده کن.

const fetchData = async (id: number): Promise<{ id: number; data: string }> => {
  if (Math.random() > 0.7) {
    throw new Error('Failed to fetch data for ID ' + id);
  }
  return { id: id, data: 'Data for ' + id };
};

async function processBatch(ids: number[]): Promise<{ successful: unknown[]; failed: unknown[] }> {
  const tasks = ids.map((id) => fetchData(id));
  const results = await Promise.allSettled(tasks);
  const successful = results.filter((r) => r.status === 'fulfilled');
  const failed = results.filter((r) => r.status === 'rejected');
  console.log('Successfully processed: ' + successful.length);
  console.log('Failed: ' + failed.length);
  return { successful: successful, failed: failed };
}

processBatch([1, 2, 3, 4, 5]);

مشاهده در ادیتور

کال بک های تایپ دار (Callbacks)

در کدهای قدیمی، «کال بک (Callback)» رایج است. تایپ دادن، خطاها را کم می کند.

type FetchCallback = (error: Error | null, data?: string) => void;

function fetchDataWithCallback(url: string, callback: FetchCallback): void {
  setTimeout(() => {
    try {
      callback(null, 'Response data');
    } catch (error) {
      const err = error instanceof Error ? error : new Error('Unknown error');
      callback(err);
    }
  }, 1000);
}

fetchDataWithCallback('https://api.example.com', (error, data) => {
  if (error) {
    console.error('Error:', error.message);
    return;
  }
  if (data) {
    console.log(data.toUpperCase());
  }
});

مشاهده در ادیتور

مدیریت خطا با کلاس های اختصاصی

برای خطاهای دامنه، کلاس بساز. پیام ها واضح تر و کنترل بهتر می شود.

class AppError extends Error {
  constructor(message: string, public readonly code: string, public readonly details?: unknown) {
    super(message);
    this.name = this.constructor.name;
  }
}

class NetworkError extends AppError {
  constructor(message: string, details?: unknown) {
    super(message, 'NETWORK_ERROR', details);
  }
}

class ValidationError extends AppError {
  constructor(public readonly field: string, message: string) {
    super(message, 'VALIDATION_ERROR', { field: field });
  }
}

مشاهده در ادیتور

تکرار ناهمگام (Async Iteration)

با «مولد ناهمگام (Async Generator)» داده ها را قطره ای بگیر. سپس مصرف کن.

async function* generateNumbers(): AsyncGenerator<number, void, unknown> {
  let i = 0;
  while (i < 5) {
    await new Promise((resolve) => setTimeout(resolve, 1000));
    yield i;
    i = i + 1;
  }
}

async function consumeNumbers(): Promise<void> {
  for await (const num of generateNumbers()) {
    console.log(num * 2);
  }
}

مشاهده در ادیتور

گام های عملی

  1. مشکل را به کارهای کوچک بشکن.
  2. برای هر کار یک Promise بساز.
  3. با async/await آن ها را ترکیب کن.
  4. خطاها را با try/catch مدیریت کن.
  5. برای موازی سازی از Promise.all استفاده کن.

جمع بندی سریع

  • async همیشه Promise برمی گرداند.
  • await کد را خواناتر می کند.
  • all برای موازی سازی است.
  • race برای تایم اوت عالی است.
  • allSettled گزارش کامل می دهد.

نکته: اگر نوع ها پیچیده شدند، نوع های میانجی تعریف کن. سپس کد تمیزتر می شود.

صفحات مرتبط: ادغام اعلان ها، دکوراتورها. همچنین برای تاکید سئو: برنامه نویسی ناهمگام.