منابع آموزشی و پژوهشی، برای دانشگاه و مدرسه
پشتیبانیانتشار محتوا
مسیر یادگیری

جاوااسکریپت ۲؛ دورهٔ متوسط و پروژه‌های کاربردی

دورهٔ دوم و رایگان جاوااسکریپت، تألیف تحریریه درس‌آوند؛ ادامهٔ دورهٔ «جاوااسکریپت از صفر تا پروژه». ۲۴ درس سطح متوسط با مثال عملی، تمرین و پاسخ و سه پروژهٔ مدیریت هزینه، فروشگاه و API محلی تیکت. پیش‌نیاز: تسلط بر مبانی دورهٔ اول و HTML مقدماتی. زمان هر درس برآورد مطالعه و تمرین است؛ این نسخه ویدیو ندارد.

۲۴ درس۱٬۱۰۰ دقیقه۰ درس کامل‌شده
پرسش دربارهٔ این دوره
اجرای غیرهم‌زمان و فروشگاه · درس ۱۵

۱۵. کاتالوگ کاربردی؛ جست‌وجوی فارسی، صفحه‌بندی و Debounce

دورهٔ رایگانثبت‌نام و پیشرفت یادگیری در حساب شما نگهداری می‌شود.ورود / ساخت حساب

کاتالوگ فقط چند کارت محصول نیست. کاربر باید بفهمد فیلتر چه اثری گذاشته، چند نتیجه وجود دارد و چرا صفحهٔ فعلی خالی شده است. در این درس، جست‌وجو و صفحه‌بندی را روی دادهٔ محلی طراحی می‌کنیم. رابط همراه پروژهٔ فروشگاه اکنون جست‌وجوی فارسی، دسته، مرتب‌سازی، صفحه‌بندی چهارتایی و تأخیر ۲۵۰ میلی‌ثانیه‌ای جست‌وجو دارد. ابتدا نسخهٔ کوچک الگوریتم را مستقل می‌سازیم، سپس آن را با پیاده‌سازی فایل‌های همراه مقایسه می‌کنیم.

قرارداد جست‌وجو را روشن کنید

حرف «ي» و «ی» در دادهٔ فارسی می‌تواند نتیجهٔ متفاوت بدهد. برای جست‌وجو می‌توان شکل‌های مشخصی را یکسان کرد، ولی متن اصلی نام محصول را تغییر نمی‌دهیم. این قرارداد باید محدود و مستند باشد؛ حذف بی‌حساب نویسه‌ها ممکن است دو واژهٔ متفاوت را یکی کند. نمونهٔ زیر مستقل است و در Node یا Console مرورگر اجرا می‌شود. قیمت‌ها تومان و داده‌ها ساختگی‌اند.

مثال اول؛ فیلتر، مرتب‌سازی، سپس صفحه‌بندی

javascript
const productsDemo = [
  { id: 'a', name: 'کیبورد', price: 700000 },
  { id: 'b', name: 'كيبورد کوچک', price: 500000 },
  { id: 'c', name: 'ماوس', price: 300000 },
  { id: 'd', name: 'کیبورد بی‌سیم', price: 900000 }
];
function normalizeSearch(value) {
  return String(value).trim().toLocaleLowerCase('fa')
    .replaceAll('ي', 'ی').replaceAll('ك', 'ک');
}
function catalogPage(products, { query = '', page = 1, size = 2 } = {}) {
  if (!Number.isInteger(size) || size < 1 || size > 100) throw Error('size');
  if (!Number.isInteger(page) || page < 1) throw Error('page');
  const needle = normalizeSearch(query);
  const filtered = products.filter(p => normalizeSearch(p.name).includes(needle))
    .sort((a, b) => a.price - b.price || a.id.localeCompare(b.id));
  const pages = Math.max(1, Math.ceil(filtered.length / size));
  const current = Math.min(page, pages);
  return {
    items: filtered.slice((current - 1) * size, current * size),
    total: filtered.length, page: current, pages
  };
}
console.log(catalogPage(productsDemo, { query: 'کیبورد', page: 2 }));
// items: [محصول d]، total:3، page:2، pages:2

ترتیب عملیات مهم است. اگر اول slice کنیم، جست‌وجو فقط در همان تکه انجام می‌شود و محصولات مرتبط صفحات دیگر گم می‌شوند. اگر مرتب‌سازی بعد از صفحه‌بندی باشد، هر صفحه جدا مرتب می‌شود. شکستن تساوی قیمت با شناسه هم ترتیب قابل تکرار می‌سازد. filter آرایهٔ تازه می‌سازد، بنابراین sort در این مثال آرایهٔ products را تغییر نمی‌دهد.

وقتی فیلتر عوض شد، معمولاً page را یک می‌کنیم. تابع علاوه بر آن، صفحهٔ خارج از بازه را به آخرین صفحهٔ موجود محدود می‌کند. برای نتیجهٔ خالی، این قرارداد page=1 و pages=1 دارد و total=0 تعیین‌کنندهٔ پیام خالی است. قرارداد دیگری هم ممکن است، ولی رابط و مدل باید یک معنا داشته باشند.

مثال دوم؛ جست‌وجوی آرام‌تر با امکان لغو

برای دادهٔ کوچک، جست‌وجوی فوری کاملاً مناسب است. debounce زمانی مفید است که اجرای هر جست‌وجو هزینه دارد یا درخواست شبکه می‌سازد. این الگو نتیجهٔ قدیمی شبکه را کنترل نمی‌کند؛ برای آن همچنان revision درس قبل لازم است. نمونهٔ زیر در مرورگر یا Node قابل اجراست و بعد از سه فراخوانی سریع، فقط «کتاب» را چاپ می‌کند.

javascript
function debounce(fn, delay = 250) {
  let timer;
  function delayed(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  }
  delayed.cancel = () => clearTimeout(timer);
  return delayed;
}
const searchLater = debounce(query => console.log('جست‌وجو:', query), 100);
searchLater('ک');
searchLater('کت');
searchLater('کتاب');
// خروجی پس از سپری شدن تأخیر: جست‌وجو: کتاب

در اتصال به input، مقدار رشته‌ای را همان لحظه بخوانید و به تابع بدهید؛ وابسته ماندن به یک عنصر یا شیء رویداد برای آینده، کد را دشوارتر می‌کند. هنگام بستن جزء، cancel را صدا بزنید تا callback دیرهنگام روی رابط بسته‌شده اجرا نشود. submit فرم باید جست‌وجوی نهایی را فوراً انجام دهد و تایمر معلق را لغو کند؛ کاربر با Enter نباید بی‌دلیل منتظر بماند.

اتصال به پروژه و مرز مقیاس

searchProducts در model.mjs آماده، query، category و sort را می‌گیرد و روی کاتالوگ محدود محلی کار می‌کند. تابع paginate در همان فایل، rows و گزینه‌های page و pageSize را می‌گیرد و items، page، pageCount و total برمی‌گرداند؛ دقت کنید نام pageCount در نسخهٔ همراه با pages در مثال ساده فرق دارد. تابع searchKey نیز علاوه بر نگاشت حروف، اعراب را حذف و نیم‌فاصله را برای جست‌وجو به فاصله تبدیل می‌کند. debounce کامل در projects/shared/timing.mjs متدهای cancel و flush دارد؛ flush کار معلق را فوراً اجرا می‌کند. کنترل‌های قبلی و بعدی در app.mjs از همین مدل استفاده می‌کنند. شمارش نتیجه را در یک متن قابل خواندن نمایش دهید و صفحهٔ فعال را واضح کنید. صرف تغییر رنگ دکمه برای فهمیدن وضعیت کافی نیست.

این صفحه‌بندی، همهٔ داده را قبلاً دانلود کرده است. برای ده‌ها هزار محصول، دریافت صفحه از سرور، کش، فیلتر سمت سرور و سیاست تازگی داده موضوع جداست. debounce هم جای محدودیت درخواست سرور یا کنترل سوءاستفاده را نمی‌گیرد.

تمرین مستقل و پاسخ تشریحی

جست‌وجو و صفحه را در URLSearchParams نگه دارید تا لینک قابل تکرار بسازید. ورودی page از URL رشته است؛ آن را به عدد تبدیل و سپس integer و مثبت بودن را بررسی کنید. پاسخ مناسب برای مقدار خراب به صفحهٔ یک برمی‌گردد، query را با URLSearchParams کدگذاری می‌کند و پس از تغییر جست‌وجو page را یک قرار می‌دهد. رشته‌ها را دستی به URL نچسبانید.

معیار تحویل: حرف عربی و فارسی نمونه نتیجهٔ یکسان بدهد؛ هیچ ردیفی بین صفحات تکرار نشود؛ فیلتر، ترتیب و تعداد نتیجه سازگار باشند؛ Enter جست‌وجو را فوری اجرا کند و هنگام ترک جزء تایمر باقی نماند.

منابع انگلیسی برای مطالعهٔ تکمیلی

https://developer.mozilla.org/en-US/docs/Glossary/Debounce
https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice

تألیف و مثال‌های مستقل: تحریریه درس‌آوند.

یکجا انتخاب کن، راحت‌تر دریافت کن

انتخاب‌های من ۰ منبع

مجموعهٔ مطالعه‌ات را بساز.

کنار مقاله‌ها «انتخاب» را بزنید تا چند فایل را با هم دریافت کنید.

انتخاب مقاله‌های رایگان