<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>پست‌های انتشارات یاvar</title>
        <link>https://virgool.io/yavarjs/feed</link>
        <description>yavarjs.ir
وبلاگی برای جاوااسکریپت، تایپ‌اسکریپت و نود ‌جی‌اس.</description>
        <language>fa</language>
        <pubDate>2026-06-16 13:31:18</pubDate>
        <image>
            <url>https://files.virgool.io/upload/publication/dxtdsmwrjfli/3rdgxk.png</url>
            <title>یاvar</title>
            <link>https://virgool.io/yavarjs</link>
        </image>

                    <item>
                <title>استقرار سریع و ساده اپلیکیشن NestJS روی Vercel</title>
                <link>https://virgool.io/yavarjs/%D8%A7%D8%B3%D8%AA%D9%82%D8%B1%D8%A7%D8%B1-%D8%B3%D8%B1%DB%8C%D8%B9-%D9%88-%D8%B3%D8%A7%D8%AF%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-nestjs-%D8%B1%D9%88%DB%8C-vercel-baapvdafggov</link>
                <description>بر اساس راهنمای رسمی Vercel و روش به‌روز🔔🔔🔔 بخاطر باگ‌های زیاد ویرگول در نمایش کد در مقاله، پیشنهاد میکنم مطلب رو از اینجا مطالعه کنید: لینک مقاله در وبلاگ yavarjs.irاین راهنما برای کسانی که از Express adapter استفاده می‌کنند مفید است. برای اپلیکیشن‌های NestJS که از Fastify adapter استفاده می‌کنند، لینک‌های زیر ممکن است کمک‌کننده باشد:Fastify Guide for Serverless on VercelFastify Examples on GitHub🚀 شما می‌توانید کد کامل مطرح‌شده در این مقاله را در این مخزن GitHub پیدا کنید: nestjs-on-vercelپشتیبانی Vercel از Express AppsVercel ویژگی مناسبی برای استقرار Express app ارائه می‌دهد که شامل مراحل زیر است:expose کردن شیء Express app در یک API.تعریف یک rewrite rule که تمام ترافیک ورودی را به این API هدایت کند.من برای استقرار NestJS از راهنمای رسمی Vercel برای Express استفاده کردم، به این صورت که شیء Express app زیربنایی NestJS را اکسپوز کردم.مرحله ۱ - ساخت یک اپلیکیشن NestJSاگر قبلاً یک اپ NestJS دارید، می‌توانید این مرحله را رد کنید.نصب NestJS و ایجاد اپ جدید:nest new my-appمرحله ۲ - نصب بسته‌های NPM موردنیازnpm install express @nestjs/platform-express
npm install -D @types/expressمرحله ۳ - ساخت فایل src/AppFactory.tsاین فایل به‌عنوان یک ماژول واحد عمل می‌کند که تمامی پیکربندی‌های ضروری اپلیکیشن NestJS را مدیریت کرده و هم NestJS app و هم شیء Express app زیربنایی آن را اکسپورت می‌کند.ساخت فایل AppFactory.ts در پوشه src:import { ExpressAdapter } from &amp;quot@nestjs/platform-express&amp;quotimport { NestFactory } from &amp;quot@nestjs/core&amp;quot
import express, { Request, Response } from &amp;quotexpress&amp;quot
import { Express } from &amp;quotexpress&amp;quot
import { INestApplication } from &amp;quot@nestjs/common&amp;quot
import { AppModule } from &amp;quot./app.module.js&amp;quot

export class AppFactory {
  static create(): {
    appPromise: Promise&lt;INestApplication&lt;any&gt;&gt;
    expressApp: Express
  } {
    const expressApp = express()
    const adapter = new ExpressAdapter(expressApp)
   const appPromise = NestFactory.create(AppModule, adapter)
    appPromise
      .then((app) =&gt; {
        app.enableCors({
          exposedHeaders: &amp;quot*&amp;quot,        })
        app.init()
      })
      .catch((err) =&gt; {
        throw err
      })
    expressApp.use((req: Request, res: Response, next) =&gt; {
      appPromise
        .then(async (app) =&gt; {
          await app.init()
         next()
    })
        .catch((err) =&gt; next(err))
    })
    return { appPromise, expressApp }
  }
}مرحله ۴ - ویرایش فایل src/main.tsبه‌طور پیش‌فرض، فایل src/main.ts نقطه ورودی اپلیکیشن است. این فایل را تغییر دهید تا تنها متد listen را فراخوانی کند:import { AppFactory } from &amp;quot./AppFactory.js&amp;quot

async function bootstrap() {
  const { appPromise } = AppFactory.create()
  const app = await appPromise

  await app.listen(process.env.PORT ?? 3000)
}
bootstrap()مرحله ۵ - افزودن فایل api/index.tsVercel به‌طور پیش‌فرض هر فانکشنی که در پوشه api قرار دارد را اجرا می‌کند. بنابراین، یک فایل در این پوشه ایجاد کنید که شیء Express app را اکسپورت کند:/**
 * This file exports Express instance for specifically for the deployment of the app on Vercel. */
import { AppFactory } from &amp;quot../src/AppFactory.js&amp;quot
export default AppFactory.create().expressAppمرحله ۶ - افزودن فایل vercel.jsonدر دایرکتوری روت پروژه یک فایل vercel.json ایجاد کنید تا Vercel را پیکربندی کنید:{  
  &amp;quotversion&amp;quot: 2,
&amp;quotbuildCommand&amp;quot: &amp;quotnpm run build&amp;quot,
  &amp;quotoutputDirectory&amp;quot: &amp;quot.&amp;quot,
  &amp;quotrewrites&amp;quot: [
    {
      &amp;quotsource&amp;quot: &amp;quot/(.*)&amp;quot,
      &amp;quotdestination&amp;quot: &amp;quot/api&amp;quot
    }
  ]
}مرحله ۷ - ایجاد پروژه روی Vercelتبریک 🎉! تقریباً تمام شد. حالا یک مخزن Git ایجاد کنید و کدتان را در آن push کنید. سپس وارد حساب Vercel خود شوید، یک پروژه جدید ایجاد کنید و مخزن Git را ایمپورت کنید. همچنین می‌توانید از مخزن GitHub مثال این مقاله استفاده کنید.</description>
                <category>یاvar</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Wed, 27 Nov 2024 14:12:26 +0330</pubDate>
            </item>
                    <item>
                <title>مشکلات URL و URLSearchParams</title>
                <link>https://virgool.io/yavarjs/%D9%85%D8%B4%DA%A9%D9%84%D8%A7%D8%AA-url-%D9%88-urlsearchparams-l6haewt9ozmx</link>
                <description>نوشته رو در وبلاگ یاvar بخونید: https://yavarjs.ir/posts/url-urlsearchparamsبررسی تفاوت‌های ریزی که حین کار با URLها باعث به وجود آمدن باگ‌های غیرمنتظره می‌شود.همه چیز از یک باگ شروع شدکار با URL‌ها در JavaScript و Node.js باید ساده باشد، اما یک باگ اخیر در پروژه ما، من را به دنیایی از جزئیات پیچیده در API‌های URL و URLSearchParams برد. در این پست، به بررسی این جزئیات و مشکلات احتمالی آن‌ها در کد و نحوه اجتناب از آن‌ها خواهیم پرداخت.مشکل: مدیریت URL با Axiosما این مشکل را هنگام تولید URL‌ها و اضافه کردن امضا‌های هش به آن‌ها پیدا کردیم. پارامترهای کوئری به طور یک‌پارچه percent-encode نمی‌شدند که منجر به رفتار غیرمنتظره و امضا‌های هش اشتباه می‌شد.واضح شد که تعامل بین اشیای URL و URLSearchParams نیاز به دقت بیشتری دارد.مشکل شماره 1: تفاوت بین URL.search و ()URLSearchParams.toStringاولین شگفتی تفاوت بین URL.search و ()URLSearchParams.toString بود.هنگام استفاده از searchParams. برای تغییر URL، دقت کنید، زیرا طبق مشخصات WHATWG ، شیء URLSearchParams از قوانین متفاوتی برای تعیین اینکه کدام کاراکترها باید percent-encode شوند استفاده می‌کند. به عنوان مثال، شیء URL کاراکتر تیلد ASCII (~) را percent-encode نمی‌کند، در حالی که URLSearchParams همیشه آن را encode می‌کند.// Example 1
const url = new URL(&amp;quothttps://example.com?param=foo bar&amp;quot)
console.log(url.search) // prints param=foo%20bar
console.log(url.searchParams.toString()) // prints ?param=foo+bar

// Example 2
const myURL = new URL(&amp;quothttps://example.org/abc?foo=~bar&amp;quot)
console.log(myURL.search) // prints ?foo=~bar
// Modify the URL via searchParams...
myURL.searchParams.sort()
console.log(myURL.search) // prints ?foo=%7Ebarدر پروژه ما، لازم بود به طور صریح ()url.search = url.searchParams.toString را دوباره اختصاص دهیم تا اطمینان حاصل شود که رشته کوئری به طور یکنواخت encode شده است.مشکل شماره 2: چالش علامت بعلاوهیکی دیگر از نکات ظریف این است که چگونه URLSearchParams با کاراکترهای + برخورد می‌کند. به طور پیش‌فرض، URLSearchParams کاراکتر + را به عنوان فضای خالی تفسیر می‌کند که ممکن است هنگام encode داده‌های باینری یا رشته‌های Base64 منجر به خرابی داده‌ها شود.const params = new URLSearchParams(&amp;quotbin=E+AXQB+A&amp;quot)
console.log(params.get(&amp;quotbin&amp;quot)) // &amp;quotE AXQB A&amp;quotیک راه حل این است که قبل از افزودن مقادیر به URLSearchParams از encodeURIComponent استفاده کنید:params.append(&amp;quotbin&amp;quot, encodeURIComponent(&amp;quotE+AXQB+A&amp;quot))جزئیات بیشتر در مستندات MDN موجود است.مشکل شماره 3: URLSearchParams.get در مقابل ()URLSearchParams.toStringیکی دیگر از جزئیات ظریف زمانی به وجود می‌آید که خروجی‌های URLSearchParams.get و URLSearchParams.toString را مقایسه می‌کنید. به عنوان مثال:const params = new URLSearchParams(&amp;quot?key=value&amp;key=other&amp;quot)
console.log(params.get(&amp;quotkey&amp;quot)) // &amp;quotvalue&amp;quot (اولین مورد)
console.log(params.toString()) // &amp;quotkey=value&amp;key=other&amp;quot (همه موارد سریالایز شده)در سناریوهای چند مقداری، get فقط اولین مقدار را برمی‌گرداند، در حالی که toString همه را سریالایز می‌کند.راه‌حل در کد مادر پروژه ما، مشکل را با اختصاص صریح search حل کردیم:url.search = url.searchParams.toString()
url.searchParams.set(
  &amp;quothash&amp;quot,
  cryptography.createSha256HmacBase64UrlSafe(url.href, SECRET_KEY ?? &amp;quot&amp;quot)
)این اطمینان حاصل کرد که تمام پارامترهای کوئری قبل از اضافه کردن مقدار hash به درستی encode شده بودند.ماژول querystring در Node.jsرابط کاربری WHATWG URLSearchParams و ماژول querystring هدف مشابهی دارند، اما هدف ماژول querystring عمومی‌تر است، زیرا امکان سفارشی‌سازی کاراکترهای جداکننده (&amp; و =) را فراهم می‌کند. از سوی دیگر، API URLSearchParams به طور خاص برای رشته‌های کوئری URL طراحی شده است.ماژول querystring از URLSearchParams کارآمدتر است اما یک API استاندارد نیست. از URLSearchParams زمانی استفاده کنید که عملکرد بحرانی نیست یا وقتی سازگاری با کد مرورگر مطلوب است.هنگام استفاده از URLSearchParams برخلاف ماژول querystring، کلیدهای تکراری به صورت آرایه مجاز نیستند. آرایه‌ها با استفاده از ()array.toString سریالایز می‌شوند که به سادگی همه عناصر آرایه را با کاما جدا می‌کند.const params = new URLSearchParams({
  user: &amp;quotabc&amp;quot,
  query: [&amp;quotfirst&amp;quot, &amp;quotsecond&amp;quot],
})
console.log(params.getAll(&amp;quotquery&amp;quot))
// Prints [ &#039;first,second&#039; ]
console.log(params.toString())
// Prints &#039;user=abc&amp;query=first%2Csecond&#039;با ماژول querystring، رشته کوئری &#x27;foo=bar&amp;abc=xyz&amp;abc=123&#x27; به این صورت پارس می‌شود:{
  &amp;quotfoo&amp;quot: &amp;quotbar&amp;quot,
  &amp;quotabc&amp;quot: [&amp;quotxyz&amp;quot, &amp;quot123&amp;quot]
}نکات کلیدیهنگام استفاده از URLSearchParams به نحوه مدیریت کاراکترهای خاص (مانند ~) و فضاهای خالی توجه کنید. در صورت نیاز از encodeURIComponent استفاده کنید.تفاوت بین URL.search، URLSearchParams.get و URLSearchParams.toString را برای جلوگیری از رفتار غیرمنتظره درک کنید.در Node.js از ماژول querystring استفاده کنید اگر می‌خواهید پارامترهای کوئری تکراری را به عنوان یک آرایه پارس کنید.منبع: Pitfalls of URL and URLSearchParams in JavaScript از وبلاگ Software Alchemist</description>
                <category>یاvar</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Fri, 22 Nov 2024 22:42:05 +0330</pubDate>
            </item>
                    <item>
                <title>استفاده از @ و /* در کامنت‌های چندخطی جاوااسکریپت</title>
                <link>https://virgool.io/yavarjs/%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-%D9%88-%D8%AF%D8%B1-%DA%A9%D8%A7%D9%85%D9%86%D8%AA-%D9%87%D8%A7%DB%8C-%DA%86%D9%86%D8%AF%D8%AE%D8%B7%DB%8C-cxbelat230i8</link>
                <description>نوشته رو در وبلاگ یاvar بخونید: yavarjs.ir/posts/special-symbols-multiline-commentsچجوری مشکل عدم امکان استفاده از علامت‌های خاص و رزرو‌ شده رو در کامنت‌های چندخطی (multiline comments) و JSDoc حل کنیم؟در حال اضافه کردن کامنت JSDoc به کدهام بودم که به یه مشکل اعصاب خوردن‌کن برخوردم. وقتی داشتم یک تیکه کد مثال رو توی کامنتم اضافه میکردم که داخلش از علامت /* استفاده میشد، کل بلوک کامنتم خراب میشد. دلیلش هم اینه که این علامت در جاوااسکریپت به عنوان تگ پایان کامنت‌های چندخطی استفاده میشه و وقتی داخل خود کامنت میخوای ازش استفاده کنی جاوااسکریپت فکر میکنه که داری بلوک کامنتت رو میبندی!این مشکل توی تیکه کد پایین قابل مشاهده‌است:/**
 * Checks whether two permission strings are semantically equal or not.
 *
 * @example
 * // returns true
 * equals(&#039;a/b/c/d/allow&#039;, &#039;a/b/c/*⁣/*/d/allow&#039;);
 *
 * @returns {boolean} True in case of equality and false otherwise.
*/
const equals = (first: string, second: string) =&gt; {
    // function&#039;s logic
    // ...

    return true; // or false
}این مشکل راه حل ساده و جالبی داره: باید یه کاراکتر جداکننده‌ی مخفی بین * و / قرار داده بشه! این کاراکتر یونیکد که اسمش هست Unicode invisible separator character باعث میشه که جاوااسکریپت علامت پایان کامنت رو تشخیص نده. این کاراکتر رو میتونید از اینجا کپی کنید.دقیقا مشابه همین مشکل وقتی به وجود میاد که بخواید از علامت @ داخل کامنت‌های JSDoc استفاده کنید. چون این علامت معنی خاصی برای JSDoc داره باعث خراب شدن داکیومنتی میشه که JSDoc تولید میکنه. به این تیکه کد یه نگاه بندازید:/**
 * A NestJS handler decorator that defines an access permission constraint and enforces it.
 *
 * @example
 * `⁣`⁣`ts
 * // the request only needs to be authenticated and doesn&#039;t need any specific permissions
 * @RequiresAccess()
 * Class MyController {}
 * `⁣`⁣`
 */
export const RequiresAccess = Reflector.createDecorator&lt;
  PermissionPathGen | PermissionPathGen[]
&gt;({
  transform(value) {
    return value == undefined ? MUST_BE_AUTHENTICATED : value
  },
})حل این مشکل هم مشابه قبلیه؛ کافیه یه کاراکتر جداکننده‌ی مخفی قبل از علامت @ قرار بدید.منبع: Using @ and */ symbols inside JS multiline comments از وبلاگ Software Alchemist</description>
                <category>یاvar</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Sun, 14 Apr 2024 23:56:38 +0330</pubDate>
            </item>
                    <item>
                <title>کمربند سیاهِ Async Await در Node.js</title>
                <link>https://virgool.io/yavarjs/mastering-async-await-rsotdpvg6tbo</link>
                <description>نوشته رو در وبلاگ یاvar بخونید: yavarjs.ir/posts/mastering-async-awaitدر این نوشته یاد میگیری که چجوری اپلیکیشن‌های Node.jsای که با callback یا Promise نوشتی رو با توابع async ساده‌ترشون کنی.اگه قبلا یه نگاهی به الگوی async/await و promiseها در جاوااسکریپت انداختی ولی هنوز کامل بهشون مسلط نیستی و یا این که فقط نیاز داری تا مرورشون کنی، هدف این نوشته کمک به توئه.تابع‌های async چی هستن؟توابع async به طور پیش‌فرض در Node در دسترسند و با کلمه‌ی کلیدی async علامت‌گذاری میشن. این توابع حتی اگه به طور صریح در بدنشون مشخص نکنی، همیشه یه promise برمیگردونن. در ضمن، فعلا کلمه‌ی کلیدی await فقط در داخل توابع async قابل استفاده‌اس و نمیشه در دامنه سراسری (global scope) ازش استفاده کرد.داخل یه تابع async میتونی منتظر یه Promise بمونی و یا این که در صورت مردود شدنش (rejected) میتونی خطاش رو دستگیر کنی (catch).پس اگه یه کدی داری که با promiseها پیاده‌سازی شده:function handler (req, res) {
  return request(&#039;https://user-handler-service&#039;)
    .catch((err) =&gt; {
      logger.error(&#039;Http error&#039;, err);
      error.logged = true;
      throw err;
    })
    .then((response) =&gt; Mongo.findOne({ user: response.body.user }))
    .catch((err) =&gt; {
      !error.logged &amp;&amp; logger.error(&#039;Mongo error&#039;, err);
      error.logged = true;
      throw err;
    })
    .then((document) =&gt; executeLogic(req, res, document))
    .catch((err) =&gt; {
      !error.logged &amp;&amp; console.error(err);
      res.status(500).send();
    });
}میتونی با ‍‍async/await شبیه به یه کد همگام (synchronous) بنویسیش:async function handler (req, res) {
  let response;
  try {
    response = await request(&#039;https://user-handler-service&#039;)  ;
  } catch (err) {
    logger.error(&#039;Http error&#039;, err);
    return res.status(500).send();
  }

  let document;
  try {
    document = await Mongo.findOne({ user: response.body.user });
  } catch (err) {
    logger.error(&#039;Mongo error&#039;, err);
    return res.status(500).send();
  }

  executeLogic(document, req, res);
}در حال حاضر در Node اگه در یه promise خطایی رخ بده که بهش رسیدگی نشده، Node فقط بهت هشدار میده، پس بنابراین نیازی نیست تا خودتو توی دردسر ساختن یه listener بندازی. هرچند چون این اتفاق نشون‌دهنده‌ی یه حالت نامشخصه، توصیه میشه تا اپلیکیشن رو ببندی و کرش کنی؛ دقیقا شبیه به حالتی که یه خطای catch نشده در جایی از کد رخ میده. این کارو میتونی یا با استفاده از پرچم unhandled-rejections=strict-- در کامند‌لاین انجام بدی یا با پیاده‌سازی چیزی شبیه به این:process.on(&#039;unhandledRejection&#039;, (err) =&gt; { 
  console.error(err);
  process.exit(1);
})قراره تا قابلیت خارج شدن اتوماتیک از پروسه، در نسخه‌های آینده‌ی Node اضافه بشه. این که کدت رو از قبل برای اینکار آماده کنی زحمت زیادی نداره ولی خوبیش اینه که وقتی خواستی نسخه‌ها رو آپدیت کنی دیگه نگران این موضوع نیستی.الگوها با توابع asyncاز اونجایی که رسیدگی به عملیات ناهمگام (asynchronous) با استفاده از Promiseها و یا callbackها نیاز به الگوهای پیچیده‌ای داره، وقتی که بتونی این عملیات رو جوری پیاده‌سازی کنی که انگار همگام هستن، کار خیلی برات ساده‌تره.از نسخه‌ی 10.0.0 نود جی‌اس، پشتیبانی از async iterators و حلقه‌ی مرتبطش یعنی for-await اضافه شده. این امکانات زمانی بدردت میخورن که میخوای روی مقداری که یه iterator method برمیگردونه و از قبل مشخص نیستن، حرکت کنی (حلقه بزنی) و کاری رو انجام بدی و حالت نهایی این تکرار (iteration) هم مشخص نیست - معمولا این حالت حین کار با streamها پیش میاد.تلاش مجدد با عقب‌نشینی نمایی (exponential backoff)پیاده‌سازی الگوریتم تلاش مجدد با Promiseها خیلی بدترکیبه:function request(url) {
  return new Promise((resolve, reject) =&gt; {
    setTimeout&#40;(&#41; =&gt; {
      reject(`Network error when trying to reach ${url}`);
    }, 500);
  });
}

function requestWithRetry(url, retryCount, currentTries = 1) {
  return new Promise((resolve, reject) =&gt; {
    if (currentTries &lt;= retryCount) {
      const timeout = (Math.pow(2, currentTries) - 1) * 100;
      request(url)
        .then(resolve)
        .catch((error) =&gt; {
          setTimeout&#40;(&#41; =&gt; {
            console.log(&#039;Error: &#039;, error);
            console.log(`Waiting ${timeout} ms`);
            requestWithRetry(url, retryCount, currentTries + 1);
          }, timeout);
        });
    } else {
      console.log(&#039;No retries left, giving up.&#039;);
      reject(&#039;No retries left, giving up.&#039;);
    }
  });
}

requestWithRetry(&#039;http://localhost:3000&#039;)
  .then((res) =&gt; {
    console.log(res)
  })
  .catch(err =&gt; {
    console.error(err)
  });این پیاده‌سازی کاری که میخوایمو میکنه اما میتونیم بازنویسیش کنیم و با async/await خیلی راحت‌تر کارو انجام بدیم:function wait (timeout) {
  return new Promise((resolve) =&gt; {
    setTimeout&#40;(&#41; =&gt; {
      resolve()
    }, timeout);
  });
}

async function requestWithRetry (url) {
  const MAX_RETRIES = 10;
  for (let i = 0; i &lt;= MAX_RETRIES; i++) {
    try {
      return await request(url);
    } catch (err) {
      const timeout = Math.pow(2, i);
      console.log(&#039;Waiting&#039;, timeout, &#039;ms&#039;);
      await wait(timeout);
      console.log(&#039;Retrying&#039;, err.message, i);
    }
  }
}خیلی بیشتر به دل میشینه، نه؟مقادیر میانی (intermediate values)با این که مثال پیش‌رو به اندازه‌ی قبلی ترسناک نیست، اما اگه حالتی داشته باشی که ۳ تابع ناهمگام مختلف به شکلی که در زیر توضیح میدم، بهم وابسته باشن، مجبوری تا از بین چندتا راه‌حل زشت و بدترکیب یکیشونو انتخاب کنی.تابع functionA یه Promise برمیگردونه که سپس functionB به مقدارش نیاز داره و بعد از اون functionC به مقدار نهایی Promiseهای جفت تابع functionA و functionB نیاز داره.راه حل ۱: درخت کریسمس then.function executeAsyncTask () {
  return functionA()
    .then((valueA) =&gt; {
      return functionB(valueA)
        .then((valueB) =&gt; {          
          return functionC(valueA, valueB)
        })
    })
}توی این راه حل، برای انجام functionC مقدار valueA رو از کلوژر (closure) سومین then میگیری و مقدار valueB رو از Promise قبلش که انجام شده. نمیتونی این درخت کریسمس رو مسطح کنی چون در اون صورت کلوژر رو گم میکنی و valueA در دسترس functionC نخواهد بود.راه حل ۲: حرکت به یه اسکوپ (scope) بالاترfunction executeAsyncTask () {
  let valueA
  return functionA()
    .then((v) =&gt; {
      valueA = v
      return functionB(valueA)
    })
    .then((valueB) =&gt; {
      return functionC(valueA, valueB)
    })
}توی مثال درخت کریسمس شبیه به همین مثال، از یه اسکوپ بالاتر برای دسترسی به valueA استفاده کردیم. اما تفاوت این مثال اینه که متغیر valueA رو خارج از اسکوپ then. تعریف کردیم تا بتونیم مقدار نهایی اولین Promise رو بهش انتساب بدیم.این مثال قطعا کار میکنه و زنجیره‌ی then. هم مسطح شده و از نظر معنایی هم درسته. با این وجود اگه از valueA در جاهای دیگه از تابع استفاده کنی، راه برای پیدا شدن باگ‌های جدید باز میشه. علاوه بر این، مجبوری برای یه مقدار یکسان از دوتا اسم مختلف استفاده کنی - valueA و v.راه حل ۳: آرایه‌ی غیر ضروریfunction executeAsyncTask () {
  return functionA()
    .then(valueA =&gt; {
      return Promise.all([valueA, functionB(valueA)])
    })
    .then(([valueA, valueB]) =&gt; {
      return functionC(valueA, valueB)
    })
}جز این که میخوای درخت رو مسطح کنی، هیچ دلیلی نداره که valueA رو همراه با Promiseای که functionB برمیگردونه داخل یه آرایه پاس بدیم. مقدار این دو عنصر آرایه ممکنه از دو جنس کاملا مختلف باشن و بنابراین جالب نیست که توی یه آرایه‌ی واحد قرار بگیرن.راه حل ۴: یه تابع کمکی بنویسconst converge = (...promises) =&gt; (...args) =&gt; {
  let [head, ...tail] = promises
  if (tail.length) {
    return head(...args)
      .then((value) =&gt; converge(...tail)(...args.concat([value])))
  } else {
    return head(...args)
  }
}

functionA(2)
  .then((valueA) =&gt; converge(functionB, functionC)(valueA))البته که میتونی یه تابع کمکی بنویسی تا این آش شله قلمکار رو درست کنی. اما از نظر خوانایی خیلی ضعیفه و بنابراین ممکنه درکش برای کسایی که توی برنامه‌نویسی functional موهاشون سفید نشده، سخت باشه.با استفاده از async/await به طور معجزه‌آسایی مشکلاتمون ناپدید میشه:async function executeAsyncTask () {
  const valueA = await functionA();
  const valueB = await functionB(valueA);
  return function3(valueA, valueB);
}چندین درخواست موازی با async/awaitاین مثال شبیه قبلیه. فرض کن میخوای چند کار ناهمگام مختلف رو در یک لحظه شروع کنی و از مقادیر برگشتیشون تو جاهای مختلف استفاده کنی:async function executeParallelAsyncTasks () {
  const [ valueA, valueB, valueC ] = await Promise.all([ functionA(), functionB(), functionC() ]);
  doSomethingWith(valueA);
  doSomethingElseWith(valueB);
  doAnotherThingWith(valueC);
}متدهای iteration آرایهاگرچه رفتارشون خیلی غیرمنتظرست ولی میتونی map ،filter و reduce رو با توابع async استفاده کنی. تلاش کن حدس بزنی که خروجی اسکریپت‌های زیر چیه:‍‍۱. mapfunction asyncThing (value) {
  return new Promise((resolve) =&gt; {
    setTimeout&#40;(&#41; =&gt; resolve(value), 100);
  });
}

async function main () {
  return [1,2,3,4].map(async (value) =&gt; {
    const v = await asyncThing(value);
    return v * 2;
  });
}

main()
  .then(v =&gt; console.log(v))
  .catch(err =&gt; console.error(err));‍‍۲. filterfunction asyncThing (value) {
  return new Promise((resolve) =&gt; {
    setTimeout&#40;(&#41; =&gt; resolve(value), 100);
  });
}

async function main () {
  return [1,2,3,4].filter(async (value) =&gt; {
    const v = await asyncThing(value);
    return v % 2 === 0;
  });
}

main()
  .then(v =&gt; console.log(v))
  .catch(err =&gt; console.error(err));‍‍۳. reducefunction asyncThing (value) {
  return new Promise((resolve) =&gt; {
    setTimeout&#40;(&#41; =&gt; resolve(value), 100);
  });
}

async function main () {
  return [1,2,3,4].reduce(async (acc, value) =&gt; {
    return await acc + await asyncThing(value);
  }, Promise.resolve(0));
}

main()
  .then(v =&gt; console.log(v))
  .catch(err =&gt; console.error(err));راه حل‌ها:۱.[ Promise { &lt;pending&gt; }, Promise { &lt;pending&gt; }, Promise { &lt;pending&gt; }, Promise { &lt;pending&gt; } ]۲.[ 4 ,3 ,2 ,1 ]۳. 10اگه خروجی هرکدوم از promiseهایی که map برمیگردونه رو چاپ کنی، میبینی که نتیجه‌ای که مورد انتظاره میده: [ 8 ,6 ,4 ,2 ]. تنها مشکل اینه که هرکدوم از این مقادیر توسط AsyncFunction توی یه Promise بسته‌بندی شدن.پس اگه میخوای مقادیرتو بگیری، باید آرایه‌ی برگشتی رو به Promise.all پاس بدی:main()
  .then(v =&gt; Promise.all(v))
  .then(v =&gt; console.log(v))
  .catch(err =&gt; console.error(err));بدون async/await باید اول منتظر تموم شدن promiseها میموندی و بعد روی مقادیرشون map رو اجرا میکردی:function main () {
  return Promise.all([1,2,3,4].map((value) =&gt; asyncThing(value)));
}

main()
  .then(values =&gt; values.map((value) =&gt; value * 2))
  .then(v =&gt; console.log(v))
  .catch(err =&gt; console.error(err));روش دوم یکم واضح‌تره، نه؟روشی که از async/await استفاده میکنه زمانی که برای هر مقدار promise نیازه تا کارهای همگام طولانی بکنی و در عین حال کارهای ناهمگام هم طولانی‌اند، میتونه بدردت بخوره.با این روش، به محض این که اولین مقدار رو بدست بیاری، میتونی محاسبتش رو شروع کنی و مجبور نیسی برای شروع محاسباتت منتظر بقیه‌ی Promiseها بمونی تا تکمیل بشن. اگرچه خروجی نهایی مقادیر توی Promiseها پیچیده شدن، اما این Promiseها خیلی سریع تکمیل میشن و در نهایت کل فرآیند سریع‌تر از زمانیه که بخوای به طور متوالی انجامش بدی.داستان filter چیه؟ مطمئنا یه چیزی این وسط اشتباهه…خب، درست حدس زدی: اگرچه مقادیر برگشتی از این قراره: [ false, true, false, true ] اما هرکدومشون توی یه Promise پیچیده شدن، و از اونجایی که هر Promise یه مقدار اصطلاحا truthy هست (یعنی زمانیه که به شکل بولین ببینیمش، مقدارش true میشه)، تمام مقادیر آرایه برمیگردن و هیچکدوم فیلتر نمیشن. متاسفانه تنها کاری که برای رفع این مشکل از دستت برمیاد اینه که اول منتظر بشی تا مقادیر Promiseها برگردن و بعد فیلترشون کنی.متد reduce خیلی سرراسته. اگرچه یادت باشه که باید مقدار اولیه رو داخل Promise.resolve بپیچی، و همچنین مقدار متغیر تجمعی هم به صورت Promise برمیگرده و بنابراین نیازه تا براش از await استفاده کنی.بازنویسی اپلیکیشن‌های برپایه‌ی callbackتوابع async به طور پیشفرض یه Promise برمیگردونن، بنابراین میتونی هر تابعی که برپایه‌ی callback هست رو جوری بازنویسی کنی که از Promiseها استفاده کنه و سپس مقدار بازگشتیش رو با await بگیری. توی Node.js برای تبدیل یه تابع برپایه‌ی callback به یه تابع برپایه‌ی Promise میتونی از تابع util.promisify استفاده کنی.بازنویسی اپلیکیشن‌های برپایه‌ی Promiseزنجیره‌های ساده‌ی then. رو خیلی سرراست میشه با استفاده از async/await بازنویسی کرد.function asyncTask () {
  return functionA()
    .then((valueA) =&gt; functionB(valueA))
    .then((valueB) =&gt; functionC(valueB))
    .then((valueC) =&gt; functionD(valueC))
    .catch((err) =&gt; logger.error(err))
}تبدیل میشه به:async function asyncTask () {
  try {
    const valueA = await functionA();
    const valueB = await functionB(valueA);
    const valueC = await functionC(valueB);
    return await functionD(valueC);
  } catch (err) {
    logger.error(err);
  }
}اپلیکیشن‌های Node.js رو با async/await بازنویسی کن اگه:مفاهیم قدیمی و باحالی مثل شرط‌های if-else و حلقه‌های for/while رو دوس داری.باور داری که بلوک‌های try-catch راه درست رسیدگی به خطاهاست.همونطور که باهم دیدیم، استفاده از async/await هم خوانایی کدهارو بیشتر میکنه و هم نوشتنشون رو ساده‌تر میکنه و در بسیاری از کارها مناسب‌تر از زنجیره‌های ()Promise.then هست. اما اگه به شور و اشتیاقی که در چند سال اخیر برای برنامه‌نویسی فانکشنال بوجود اومده دچار شدی، شاید بهتر باشه که از خیر این قابلیت جاوااسکریپت بگذری.منبع: Rewriting Node.js apps with async/await از وبلاگ RisingStack</description>
                <category>یاvar</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Sun, 02 May 2021 17:40:26 +0430</pubDate>
            </item>
                    <item>
                <title>تنظیم Docker برای یه وب‌اپ Node.js</title>
                <link>https://virgool.io/yavarjs/dockerizing-nodejs-mqd4ijcjbcom</link>
                <description>نوشته رو در وبلاگ یاvar بخونید: yavarjs.ir/posts/dockerizing-nodejsهدف این نوشته معرفی یه مثاله برای این که چجوری یه اپلیکیشن Node.js رو به یه کانتینر Docker تبدیل کنی. این راهنما برای زمان توسعه اپ هست و نه برای استقرار اپ برای production. همچنین فرض میکنم که یه نسخه‌ی نصب شده از داکر روی سیستمت هست و یه دانش ابتدایی از ساختار یه اپلیکیشن Node.js داری.در بخش اول این راهنما یه وب‌اپلیکیشن ساده رو با Node.js میسازی و سپس یه image داکر برای اون اپلکیشن درست میکنی و در آخر هم یه کانتینر رو از روی اون image اجرا میکنی.داکر این امکان رو بهت میده که یه اپلیکیشن رو با محیطش (environment) و تمام وابستگی‌هاش (dependencies) به یه جعبه تبدیل کنی که اسمش هست «کانتینر» (container). معمولا یه کانتینر از یه اپلکیشن تشکیل شده که روی یه سیستم‌عامل لینوکس خیلی سبک و ساده در حال اجراست. یه image یه نقشه و طرح برای کانتینره و یه کانتینر یه نمونه در حال اجرا از یه image هست.ساخت اپ Node.jsدر ابتدا یه فولدر بساز که تمام فایلها قراره اونجا زندگی کنن. توی این فولدر یه فایل package.json بساز که توضیحاتیه درمورد اپ و وابستگی‌هاش:{
  &amp;quotname&amp;quot: &amp;quotdocker_web_app&amp;quot,
  &amp;quotversion&amp;quot: &amp;quot1.0.0&amp;quot,
  &amp;quotdescription&amp;quot: &amp;quotNode.js on Docker&amp;quot,
  &amp;quotauthor&amp;quot: &amp;quotFirst Last &lt;first.last@example.com&gt;&amp;quot,
  &amp;quotmain&amp;quot: &amp;quotserver.js&amp;quot,
  &amp;quotscripts&amp;quot: {
    &amp;quotstart&amp;quot: &amp;quotnode server.js&amp;quot
  },
  &amp;quotdependencies&amp;quot: {
    &amp;quotexpress&amp;quot: &amp;quot^4.16.1&amp;quot
  }
}دستور npm install رو اجرا کن. اگه از نسخه‌ی ۵ به بالای npm استفاده میکنی، این دستور یه فایل package-lock.json درست میکنه که بعدا کپی میشه به image داکرت.سپس یه فایل server.js بساز که یه وب‌اپ رو شامل میشه که از فریمورک Express.js استفاده میکنه:&#039;use strict&#039;;

const express = require(&#039;express&#039;);

// مقادیر ثابت
const PORT = 8080;
const HOST = &#039;0.0.0.0&#039;;

// اپ
const app = express();
app.get(&#039;/&#039;, (req, res) =&gt; {
  res.send(&#039;Hello World&#039;);
});

app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);توی مراحل بعدی، میبینی که چجوری میتونی این اپ رو با استفاده از ایمیج رسمی داکر، داخل یه کانتینر اجراش کنی. اول از همه نیاز داری تا یه Docker image برای اپلیکیشنت بسازی.ایجاد یه Dockerfileیه فایل خالی بساز که اسمش هست Dockerfile:touch Dockerfileاین فایل رو داخل ادیتور مورد علاقت باز کن.اولین کار اینه که ببینیم از چه ایمیجی کارمون رو شروع کنیم. اینجا از آخرین نسخه‌ی پشتیبانی بلندمدت (LTS) استفاده میکنیم که میشه نسخه‌ی ‍14 از node که در مخزن Docker Hub موجوده:FROM node:14سپس توی ایمیج یه فولدر بساز که داخلش کدهای اپلیکیشن رو قرار بدی، این فولدر قراره فولدر کاری (working directory) برای اپلیکیشنت باشه:# رو بساز app دایرکتوری
WORKDIR /usr/src/appایمیج (node:14) از قبل داخلش Node.js و NPM نصب شده و کار بعدی که نیازه بکنی اینه که وابستگی‌های اپلیکیشنت رو با npm نصب کنی. لطفا دقت کن که اگه داری از نسخه‌ی ۴ به پایین npm استفاده میکنی، فایل package-lock.json ساخته نمیشه.# وابستگی‌های اپ رو نصب کن
# از علامت ستاره استفاده شده تا هم فایل قفل و هم فایل عادی کپی بشه
COPY package*.json ./

RUN npm install
# اگه داری اپلیکیشن رو برای پروداکشن میسازی از دستور زیر استفاده کن
# RUN npm ci --only=productionدقت کن که به جای کپی کردن کل فولدر کاریمون، فقط فایل package.json رو کپی کردیم. این کار بهمون اجازه میده تا از مزیت لایه‌های قابل کش در داکر استفاده کنیم ( بیشتر بخوانید ). علاوه‌بر این، فرمان npm ci کمک میکنه که build های سریعتر، قابل اتکاتر و قابل تکثیر برای محیط‌های پروداکشن بسازیم. در این مورد میتونی اینجا بیشتر بخونی.برای بسته‌بندی کردن سورس‌کدهای اپ توی ایمیج داکر، از دستور COPY استفاده کن:# سورس اپ رو بسته‌بندی کن
COPY . .اپلیکیشنت خودشو به پورت 8080 میچسبونه، پس از دستور EXPOSE استفاده کن تا داکر این پورت رو برات مپ کنه:EXPOSE 8080در آخر، فرمانی که اپلیکیشنت رو به اجرا درمیاره با استفاده از CMD تعریف کن. در اینجا ما از ‍node server.js برای شروع سرور استفاده میکنیم:CMD [ &amp;quotnode&amp;quot, &amp;quotserver.js&amp;quot ]فایل dockerfile الان باید اینشکلی باشه:FROM node:14

# رو بساز app دایرکتوری
WORKDIR /usr/src/app

# وابستگی‌های اپ رو نصب کن
# از علامت ستاره استفاده شده تا هم فایل قفل و هم فایل عادی کپی بشه
COPY package*.json ./

RUN npm install
# اگه داری اپلیکیشن رو برای پروداکشن میسازی از دستور زیر استفاده کن

# سورس اپ رو بسته‌بندی کن
COPY . .

EXPOSE 8080
CMD [ &amp;quotnode&amp;quot, &amp;quotserver.js&amp;quot ]فایل dockerignore.یه فایل ‍‍dockerignore داخل همون فولدری که فایل dockerfile هست بساز که محتواش ایناس:node_modules
npm-debug.logاینکار باعث میشه که ماژول‌های محلی (ماژول‌هایی که روی سیستم خودت داخل فولدر اپ نصب کردی) و لاگ‌های دیباگ توی ایمیج داکر کپی نشه.ساخت imageبرو به فولدری که dockerfile داخلشه و فرمان زیر رو اجرا کن تا ایمیج داکر رو بسازه. پرچم t- یه برچسب به ایمیج میچسبونه که بعدا راحت‌تر بتونی با فرمان docker images پیداش کنی:docker build . -t &lt;your username&gt;/node-web-appحالا باید داکر ایمیجت رو لیست کرده باشه:$ docker images

# مثال
REPOSITORY                      TAG        ID              CREATED
node                            14         1934b0b038d1    5 days ago
&lt;your username&gt;/node-web-app    latest     d64d3505b0d2    1 minute agoاجرای imageاجرا کردن ایمیجل با پرچم d- کانتینر رو در پس‌زمینه اجرا میکنه. پرچم p- یه پورت خصوصی داخل کانتینر رو به یه پورت عمومی ریدایرکت میکنه. ایمیجی که از قبل ساختی رو اجرا کن:docker run -p 49160:8080 -d &lt;your username&gt;/node-web-appخروجی اپلیکیشنت رو چاپ کن:$ docker ps
# خروجی اپ رو چاپ کن
$ docker logs &lt;container id&gt;

# مثال
Running on http://localhost:8080اگه میخوای بری داخل خود کانتینر، میتونی از فرمان exec استفاده کنی:$ docker exec -it &lt;container id&gt; /bin/bashتستبرای این که اپلیکیشنت رو تست کنی، پورتی رو که داکر مپ کرده پیدا کن:$ docker ps

# مثال
ID            IMAGE                                COMMAND    ...   PORTS
ecce33b30ebf  &lt;your username&gt;/node-web-app:latest  npm start  ...   49160-&gt;8080توی مثال بالا، داکر پورت داخلی 8080 کانتینر رو به پورت 49160 روی کامپیوترت مپ کرده.حالا اپلیکیشنت رو با استفاده از curl فراخوانی کن:$ curl -i localhost:49160

HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 12
ETag: W/&amp;quotc-M6tWOb/Y57lesdjQuHeB1P/qTV0&amp;quot
Date: Mon, 13 Nov 2017 20:53:59 GMT
Connection: keep-alive

Hello worldامیدوارم این خودآموز بهت کمک کرده باشه که بتونی یه اپلیکیشن ساده Node.js رو با Docker اجرا کنی.منبع: Dockerizing a Node.js web app از وبسایت رسمی نود جی‌اس</description>
                <category>یاvar</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Thu, 29 Apr 2021 16:07:43 +0430</pubDate>
            </item>
                    <item>
                <title>انواع loop برای آرایه‌ها: for و for-in و ()forEach. و for-of</title>
                <link>https://virgool.io/yavarjs/looping-over-arrays-imjsa9ifnwxs</link>
                <description>نوشته رو در وبلاگ یاvar بخونید: yavarjs.ir/posts/looping-over-arraysدر این نوشته چهار روش مختلف برای استفاده از حلقه‌ها روی آرایه‌ها رو مقایسه می‌کنیم.حلقه‌ی for:for (let index=0; index &lt; someArray.length; index++) {
  const elem = someArray[index];
  // ···
}حلقه‌ی for-in:for (const key in someArray) {
  console.log(key);
}متد ()forEach. از کلاس Array:someArray.forEach((elem, index) =&gt; {
  console.log(elem, index);
});حلقه‌ی for-of:for (const elem of someArray) {
  console.log(elem);
}حلقه‌ی for-of در اغلب موارد بهترین انتخابه. در ادامه میبینم چرا.۱ - حلقه‌ی for [جاوااسکریپت ES1]حلقه‌ی ساده for در جاوااسکریپت قدمت داره و از نسخه‌ی ۱ ECMAScript وجود داشته. حلقه زیر اندیس و مقدار هر عنصر آرایه arr رو چاپ میکنه:const arr = [&#039;a&#039;, &#039;b&#039;, &#039;c&#039;];
arr.prop = &#039;property value&#039;;

for (let index=0; index &lt; arr.length; index++) {
  const elem = arr[index];
  console.log(index, elem);
}

// Output:
// 0, &#039;a&#039;
// 1, &#039;b&#039;
// 2, &#039;c&#039;نقاط مثبت و منفی این حلقه چیه؟کاملا همه‌کارس اما از طرفی وقتی فقط میخوایم روی آرایه حلقه بزنیم، نوشتنش طولانی و پرجزئیاته.اگه نمیخوایم از اولین عنصر آرایه شروع کنیم، این حلقه خیلی بدردبخوره. هیچکدوم از روش‌های دیگه این امکان رو بهمون نمیدن.۲ - حلقه‌ی for-in [جاوااسکریپت ES1] حلقه‌ی for-in به اندازه‌ی حلقه‌ی for قدمت داره. حلقه‌ی زیر کلید‌های آرایه‌ی arr رو چاپ میکنه:const arr = [&#039;a&#039;, &#039;b&#039;, &#039;c&#039;];
arr.prop = &#039;property value&#039;;

for (const key in arr) {
  console.log(key);
}

// Output:
// &#039;0&#039;
// &#039;1&#039;
// &#039;2&#039;
// &#039;prop&#039;for-in انتخاب خوبی برای حلقه‌زدن روی آرایه‌های نیست، چون:کلیدهای property رو مرور میکنه و نه مقادیر رو.اندیس‌های آرایه وقتی به صورت کلید‌های property دیده‌میشن، به جای این که عدد باشن، از جنس string هستن. ( اطلاعات بیشتر درمورد نحوه کار عناصر آرایه‌ها )به جای اندیس عناصر آرایه، تمام کلید‌های property که قابل شمارش هستن (enumerable) رو مرور میکنه (هم اونایی که مال خود آرایه هستن و هم اونایی که به ارث رسیدن).این ویژگی for-in که تمام propertyهای به ارث‌رسیده رو مرور میکنه یه جا کاربرد داره: زمانی که میخوایم روی propertyهای قابل شمارش یه object حلقه بزنیم. اما حتی در اون مورد هم حلقه زدن روی زنجیره prototype به شکل دستی بهتره، چون کنترل بیشتری در اختیارمون میذاره.۳ - متد ()forEach. [جاوااسکریپت ES5]با توجه به این که نه حلقه‌ی for و نه حلقه‌ی for-in انتخاب‌های خوبی برای حلقه‌زدن روی آرایه‌ها نیستن، یه متد کمکی در ECMAScript 5 معرفی شد: ()Array.prototype.forEach:const arr = [&#039;a&#039;, &#039;b&#039;, &#039;c&#039;];
arr.prop = &#039;property value&#039;;

arr.forEach((elem, index) =&gt; {
  console.log(elem, index);
});

// Output:
// &#039;a&#039;, 0
// &#039;b&#039;, 1
// &#039;c&#039;, 2این متد خیلی راحته: بدون نیاز به انجام کار زیاد ، هم دسترسی به اندیس و هم به عناصر آرایه رو میده. تابع‌های فِلشی (Arrow functions) که در ES6 معرفی شدن، این متد رو از قبل هم زیباترش کرده.معایب اصلی ()forEach. از این قراره:امکان استفاده از await در «بدنه» این نوع حلقه وجود نداره.از حلقه‌ی ()forEach. نمیشه زودتر از موعد خارج شده. درصورتیکه در حلقه‌های for میشه از break استفاده کرد.۱.۳ - خارج شدن از ()forEach. - یه راه حلیه راه حل برای خارج شدن از این حلقه هست: استفاده از ()some. که روی تمام عناصر آرایه حلقه میزنه و زمانی که تابع callback یه مقدار truthy (یه مقداری که بشه به معنی true تفسیرش کرد) رو برگردونه، متوقف میشه.const arr = [&#039;red&#039;, &#039;green&#039;, &#039;blue&#039;];
arr.some((elem, index) =&gt; {
  if (index &gt;= 2) {
    return true; // از حلقه خارج میشه
  }
  console.log(elem);
   // رو برمیگردونه undefined تابع به طور ضمنی مقدار
  // هست حلقه ادامه پیدا میکنه falsy که چون یه مقدار
});

// Output:
// &#039;red&#039;
// &#039;green&#039;۴ - حلقه‌ی for-of [جاوااسکریپت ES6]این حلقه در ECMAScript 6 اضافه شد:const arr = [&#039;a&#039;, &#039;b&#039;, &#039;c&#039;];
arr.prop = &#039;property value&#039;;

for (const elem of arr) {
  console.log(elem);
}
// Output:
// &#039;a&#039;
// &#039;b&#039;
// &#039;c&#039;حلقه‌ی for-of برای حلقه زدن روی آرایه‌ها خیلی خوبه، چون:روی عناصر آرایه تکرار میشه.داخلش میتونیم از await استفاده کنیم.و اگه نیاز پیدا کنیم خیلی راحت میتونیم به for-await-of کوچ کنیم.میتونیم از break و continue استفاده کنیم - حتی در اسکوپ (scope) های بیرونی‌تر.۱.۴ - حلقه‌ی for-of و آبجکت‌های iterableیه مزیت اضافه‌ی for-of اینه که با اون نه فقط روی آرایه‌ها بلکه روی آبجکت‌های iterable هم میشه حلقه زد - برای مثال، روی Mapها:const myMap = new Map()
  .set(false, &#039;no&#039;)
  .set(true, &#039;yes&#039;)
;
for (const [key, value] of myMap) {
  console.log(key, value);
}

// Output:
// false, &#039;no&#039;
// true, &#039;yes&#039;حلقه زدن روی myMap جفت [key, value] رو برمیگردونه که در کد بالا از روش destructre کردن برای دسترسی مستقیم به مقادیر این جفت استفاده کردیم.۲.۴ - حلقه‌ی for-of و اندیس‌های آرایهمتد ()keys. در آرایه‌ها، یه iterable روی اندیس‌های آرایه رو برمیگردونه:const arr = [&#039;chocolate&#039;, &#039;vanilla&#039;, &#039;strawberry&#039;];

for (const index of arr.keys()) {
  console.log(index);
}
// Output:
// 0
// 1
// 2۳.۴ - حلقه‌ی for-of و دسترسی همزمان به مقادیر و اندیس‌ها با ()entries.متد ()entries. در آرایه‌ها یه iterable روی جفت‌های [index, value] برمیگردونه. با استفاده از for-of و destructuring خیلی راحت میتونیم روی مقادیر و اندیس‌های آرایه به طور همزمان حلقه بزنیم:const arr = [&#039;chocolate&#039;, &#039;vanilla&#039;, &#039;strawberry&#039;];

for (const [index, value] of arr.entries()) {
  console.log(index, value);
}
// Output:
// 0, &#039;chocolate&#039;
// 1, &#039;vanilla&#039;
// 2, &#039;strawberry&#039;۵ - نتیجه‌گیریهمونطور که دیدیم، وقتی معیار کاربرد باشه حلقه‌ی for-of از بقیه‌ی روش‌ها بهتره.هر تفاوتی در سرعت (performance) بین این چهار روش حلقه‌زدن، در حالت عادی نباید اهمیتی داشته باشه. اگه اهمیت داره احتمالا داری یه کار خیلی سنگین از نظر محاسباتی انجام میدی و بنابراین استفاده از WebAssembly احتمالا گزینه‌ی معقول‌تری باشه.منبع: Looping over Arrays: for vs. for-in vs. .forEach() vs. for-of از وبلاگ 2ality - JavaScript and more</description>
                <category>یاvar</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Thu, 29 Apr 2021 04:38:23 +0430</pubDate>
            </item>
                    <item>
                <title>تاریخچه typeof null در جاوا اسکریپت</title>
                <link>https://virgool.io/yavarjs/typeof-null-vdgnyfdakrob</link>
                <description>نوشته رو در وبلاگ یاvar بخونید: yavarjs.ir/posts/typeof-nullخروجی typeof null توی جاوا اسکریپت برابر میشه با &quot;object&quot; که به نادرستی این معنی رو منتقل میکنه که null یک آبجکت (شیء) هست (در صورتی که نیست. null یه primitive value یا مقدار اولیه هست). این یه باگه که چون کدهای فعلی از کار می‌افتن نمیشه رفعش کرد.باگ «typeof null» بازمانده‌ی اولین نسخه‌ی جاوااسکریپته. توی اون نسخه، مقادیر در واحدهای ۳۲‌بیتی ذخیره میشدن که از یک برچسب (tag) ۱ الی ۳ بیتی برای تشخیص نوع و از بقیه‌ی بیت‌ها برای ذخیره کردن مقدار اصلی داده استفاده میشد. «برچسب‌های نوع داده» در بیت‌های کم‌ارزش ذخیره میشدن. پنج‌تا از این برچسب‌ها وجود داشت:000: آبجکت. داده به یک آبجکت اشاره میکنه.1: عدد صحیح (int). داده یک عدد صحیح علامت‌دار (signed integer) ۳۱‌بیتی هست.010: عدد double. داده یک مرجع به یک عدد اعشاری double هست.100: رشته (string). داده یک مرجع به یک رشته هست.110: بولی (boolean). داده یک بولین است.اگه بی‌ارزش‌ترین بیت مقدارش 1 بود، برچسب نوع داده یک بیتی بود و اگه بی‌ارزش‌ترین بیت 0 بود، برچسب نوع داده ۳ بیتی بود که از دو‌ بیت اضافه‌تر، برای تعیین چهار نوع داده مختلف استفاده میشد.دو مقدار ویژه هم وجود داشتن:مقدار undefined یا JSVAL_VOID که عدد صحیح 30^2- بود (یه عدد خارج از محدوده‌ی اعداد صحیح).مقدار null یا JSVAL_NULL که کد ماشین اشاره‌گر NULL بود: یک نوع داده آبجکت که مقدار اشاره‌گرش 0 بود.الان دیگه باید واضح باشه که چرا typeof برای null مقدار آبجکت رو برمی‌گردونه: برچسبِ نوع داده رو چک میکنه و ‌میبینه که برابر با آبجکت هست. کد اولین موتور جاوا اسکریپت برای typeof: https://gist.github.com/mahdavipanah/e74e1269660aa23bdf6f57ea74f0de71 گام‌هایی که کد بالا طی میکنه:گام (1)، موتور بررسی میکنه که آیا مقدار v برابر با undefined (VOID) هست یا نه. این بررسی با انجام یه دستور برابری انجام میشه:#define JSVAL_IS_VOID(v)  ((v) == JSVAL_VOID)بررسی بعدی (2) اینه که آیا مقدار موردنظر برچسب آبجکت داره یا نه. علاوه‌بر این اگه مقدار v قابل صدا زدنه یا به عبارتی callable هست (3) یا ویژگی داخلی [[Class]] اون داره میگه که یک تابع هست (4) پس بنابراین v یک تابعه. در غیر این صورت، یک آبجکته.این نتیجه‌ایه که برای typeof null تولید میشه.بررسی‌های بعدی برای اعداد، رشته‌ها و بولین هست. هیچ بررسی صریحی برای مقدار null وجود نداره، که می‌تونست خیلی راحت با یه ماکرو C انجام بشه:#define JSVAL_IS_NULL(v)  ((v) == JSVAL_NULL)این باگ شاید خیلی واضح به نظر بیاد، اما نباید فراموش کرد که برای نوشتن اولین نسخه‌ی جاوا اسکریپت زمان خیلی کمی در اختیار بود.منبع: The history of typeof null از وبلاگ 2ality - JavaScript and more</description>
                <category>یاvar</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Sun, 18 Apr 2021 18:04:27 +0430</pubDate>
            </item>
            </channel>
</rss>