آموزش دستور try…catch…finally در جاوا اسکریپت

هرچقدر در برنامهنویسی عالی باشیم، گاهی اوقات اسکریپتهای ما دارای خطا هستند. این خطاها ممکن است به دلیل اشتباهات ما، ورودی غیرمنتظره کاربر، پاسخ اشتباه سرور و هزاران دلیل دیگر رخ دهند. معمولاً یک اسکریپت در صورت بروز خطا متوقف میشود یا به حالت dies میرود و آن را در کنسول چاپ میکند؛ اما یک ساختار نحوی try…catch در جاوا اسکریپت وجود دارد که به ما امکان میدهد خطاها را « catch » یا نادیده بگیریم تا اسکریپت بتواند بهجای توقف، کار معقولتری انجام دهد. در این پست آموزشی از مکتب خونه میخواهیم در رابطه با آموزش دستور try…catch…finally در جاوا اسکریپت باهم به گفتگو بپردازیم. پس باما همراه باشید.
سینتکس دستور try…catch در جاوا اسکریپت
ساختار try…catch در جاوا اسکریپت دو بلوک اصلی دارد، try و سپس catch. به صورت زیر:
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token comment">// code...</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// error handling</span>
<span class="token punctuation">}</span>
نحوه کار دستور try…catch…finally
نحوه کار دستور try…catch…finally در جاوا اسکریپت به صورت زیر است:
- ابتدا کد موجود در try اجرا میشود.
- اگر خطایی وجود نداشته باشد، catch (err) نادیده گرفته میشود: اجرا به پایان تلاش میرسد و ادامه مییابد و از catch میگذرد.
- اگر خطایی رخ دهد، اجرای try متوقف میشود و کنترل به ابتدای catch (err) جریان مییابد. متغیر err (میتوانیم از هر نامی برای آن استفاده کنیم) حاوی یک شیء خطا با جزئیات مربوط به اتفاقی بوده که رخداده است.
فلوچارت زیر نحوه اجرای دستور try…catch…finally را در جاوا اسکریپت بیان میکند.
بنابراین، یک خطا در بلوک try اسکریپت را به حالت متوقف نمیبرد و ما در جاوا اسکریپت این شانس را داریم که آن را بهطور کامل مدیریت کنیم.
پیشنهاد مطالعه: آموزش متد Includes در جاوا اسکریپت
مثال از try…catch…finally در جاوا اسکریپت
یک مثال بدون خطا: کد زیر هشدار (1) و (2) را نشان میدهد و این کد بدون خطا است:
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'Start of try runs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// (1)</span>
<span class="token comment">// ...no errors here</span>
<span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'End of try runs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// (2)</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'Catch is ignored, because there are no errors'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// (3)</span>
<span class="token punctuation">}</span>
یک مثال با خطا: (1) و (3) را بهعنوان ارور نشان میدهد:
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'Start of try runs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// (1)</span>
lalala<span class="token punctuation">;</span> <span class="token comment">// error, variable is not defined!</span>
<span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">'End of try (never reached)'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// (2)</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">alert</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Error has occurred!</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// (3)</span>
<span class="token punctuation">}</span>
ساختار دستور try…catch…finally در زمان اجرا
برای قابلاستفاده بودن دستور try…catch…finally در جاوا اسکریپت کد باید قابلاجرا باشد. بهعبارتدیگر، باید جاوا اسکریپت معتبر باشد.
اگر کد ازنظر نحوی اشتباه باشد، کار نمیکند، بهعنوانمثال کد زیر دارای براکت های بی همتا است:
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token punctuation">{</span><span class="token punctuation">{</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"The engine can't understand this code, it's invalid"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
موتور جاوا اسکریپت ابتدا کد را میخواند و سپس آن را اجرا میکند. خطاهایی که در مرحله خواندن رخ میدهد، خطاهای «تجزیه زمان» نامیده میشوند و غیرقابلجبران هستند، این به این دلیل است که موتور نمیتواند کد را درک کند.
بنابراین، try…catch…finally در جاوا اسکریپت فقط میتواند خطاهایی را که در کدهای معتبر رخ میدهد، کنترل کند. چنین خطاهایی خطاهای زمان اجرا یا گاهی اوقات، استثنا نامیده میشوند.
پیشنهاد مطالعه: Scope در جاوا اسکریپت چیست؟ آموزش اسکوپ به زبان ساده
دستور try…catch…finally در جاوا اسکریپت برای همزمانی
اگر یک استثنا در کد «زمانبندیشده» اتفاق بیفتد، مانند setTimeout، دستور try…catch…finally در جاوا اسکریپت آن را نمیگیرد:
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
noSuchVariable<span class="token punctuation">;</span> <span class="token comment">// script will die here</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">alert</span><span class="token punctuation">(</span> <span class="token string">"won't work"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
این به این دلیل است که خود تابع بعداً اجرا میشود، زمانی که موتور قبلاً از ساختار try…catch خارجشده است. برای گرفتن یک استثنا در داخل یک تابع زمانبندیشده، try…catch…finally باید در داخل آن تابع باشد:
<span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
noSuchVariable<span class="token punctuation">;</span> <span class="token comment">// try...catch handles the error!</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
<span class="token function">alert</span><span class="token punctuation">(</span> "error is caught here<span class="token operator">!</span>« <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
شیء خطا
هنگامیکه یک خطا رخ میدهد، جاوا اسکریپت یک شیء تولید میکند که حاوی جزئیات مربوط به آن است. سپس شیء بهعنوان آرگومان برای گرفتن ارسال میشود. به مثال زیر دقت کنید.
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// the "error object", could use another word instead of err</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span>
برای تمام خطاهای داخلی، شیء خطا دو ویژگی اصلی دارد:
- نام خطا. بهعنوانمثال، برای یک متغیر تعریفنشده که ReferenceError است.
- پیام متنی در مورد جزئیات خطا
ویژگیهای غیراستاندارد دیگری نیز در اکثر محیطها وجود دارد. یکی از پرکاربردترین و پشتیبانی شده ترین موارد در رابطه با پشته است:
پشته تماس فعلی: رشتهای با اطلاعاتی در مورد توالی تماسهای تودرتو که منجر به خطا شده است که برای اهداف اشکالزدایی استفاده میشود. برای مثال:
<span class="token keyword">try</span> <span class="token punctuation">{</span>
lalala<span class="token punctuation">;</span> <span class="token comment">// error, variable is not defined!</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">alert</span><span class="token punctuation">(</span>err<span class="token punctuation">.</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// ReferenceError</span>
<span class="token function">alert</span><span class="token punctuation">(</span>err<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// lalala is not defined</span>
<span class="token function">alert</span><span class="token punctuation">(</span>err<span class="token punctuation">.</span>stack<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// ReferenceError: lalala is not defined at (...call stack)</span>
<span class="token comment">// Can also show an error as a whole</span>
<span class="token comment">// The error is converted to string as "name: message"</span>
<span class="token function">alert</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// ReferenceError: lalala is not defined</span>
<span class="token punctuation">}</span>
استفاده از دستور try… catch
در این بخش به یک مثال عملی از try…catch…finally در جاوا اسکریپت میپردازیم تا بهخوبی نحوه استفاده از آن برای ما تفهیم شود.
همانطور که میدانیم، جاوا اسکریپت از متد JSON.parse(str) برای خواندن مقادیر کدگذاری شده با JSON پشتیبانی میکند. معمولاً برای رمزگشایی دادههای دریافتی از طریق شبکه، از سرور یا منبع دیگری استفاده میشود. ما آن را دریافت میکنیم و JSON.parse را به این صورت فراخوانی میکنیم:
<span class="token keyword">let</span> json <span class="token operator">=</span> <span class="token string">'{"name":"John", "age": 30}'</span><span class="token punctuation">;</span> <span class="token comment">// data from the server</span>
<span class="token keyword">let</span> user <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>json<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// convert the text representation to JS object</span>
<span class="token comment">// now user is an object with properties from the string</span>
<span class="token function">alert</span><span class="token punctuation">(</span> user<span class="token punctuation">.</span>name <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// John</span>
<span class="token function">alert</span><span class="token punctuation">(</span> user<span class="token punctuation">.</span>age <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 30</span>
اگر json نادرست باشد، JSON.parse خطایی ایجاد میکند، بنابراین اسکریپت به حالت توقف میرود. بهاینترتیب، اگر مشکلی در دادهها وجود داشته باشد، بازدیدکننده هرگز آن را نمیداند (مگر اینکه کنسول توسعهدهنده را باز کند و ببینند).
حال بیایید از دستور try…catch در جاوا اسکریپت برای رسیدگی به این خطا استفاده کنیم:
<span class="token keyword">let</span> json <span class="token operator">=</span> <span class="token string">"{ bad json }"</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> user <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>json<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// when an error occurs...</span>
<span class="token function">alert</span><span class="token punctuation">(</span> user<span class="token punctuation">.</span>name <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// doesn't work</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// ...the execution jumps here</span>
<span class="token function">alert</span><span class="token punctuation">(</span> "Our apologies<span class="token punctuation">,</span> the data has errors<span class="token punctuation">,</span> we'll <span class="token keyword">try</span> to request it one more time<span class="token punctuation">.</span>« <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">alert</span><span class="token punctuation">(</span> err<span class="token punctuation">.</span>name <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">alert</span><span class="token punctuation">(</span> err<span class="token punctuation">.</span>message <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
در اینجا ما از بلوک catch فقط برای نشان دادن پیام استفاده میکنیم، اما میتوانیم کارهای بیشتری انجام دهیم: ارسال یک درخواست شبکه جدید، پیشنهاد جایگزینی برای بازدیدکننده، ارسال اطلاعات مربوط به خطا به یک مرکز گزارشگیری، …. همهچیز خیلی بهتر از مردن است.
پیشنهاد مطالعه: آموزش تابع Date در جاوا اسکریپت به زبان ساده + مثال و نمونه کد
پرتاب اشتباهات خودمان
اگر json ازنظر نحوی صحیح باشد، اما ویژگی نام لازم را نداشته باشد، چه؟ مثل این:
<span class="token keyword">let</span> json <span class="token operator">=</span> <span class="token string">'{ "age": 30 }'</span><span class="token punctuation">;</span> <span class="token comment">// incomplete data</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> user <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>json<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// no errors</span>
<span class="token function">alert</span><span class="token punctuation">(</span> user<span class="token punctuation">.</span>name <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// no name!</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">alert</span><span class="token punctuation">(</span> <span class="token string">"doesn't execute"</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
در اینجا JSON.parse بهطورمعمول اجرا میشود، اما عدم وجود نام درواقع برای ما یک خطا است. برای مدیریت خطا در این صورت از عملگر throw استفاده میکنیم.
اپراتور throw یا عملگر پرتاب
عملگر throw در جاوا اسکریپت یک خطا ایجاد میکند. سینتکس آن بهصورت زیر است:
<span class="token keyword">throw</span> <span class="token operator"><</span>error object<span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>error<span class="token operator">></span>
ازنظر فنی، ما میتوانیم از هر چیزی بهعنوان یک شیء خطا استفاده کنیم.
جاوا اسکریپت سازندههای داخلی زیادی برای خطاهای استاندارد دارد: Error، SyntaxError، ReferenceError، TypeError و غیره. ما میتوانیم از آنها برای ایجاد اشیاء خطا نیز استفاده کنیم. سینتکس آنها به این صورت است:
<span class="token keyword">let</span> error <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// or</span>
<span class="token keyword">let</span> error <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SyntaxError</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> error <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ReferenceError</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// ...</span>
برای خطاهای داخلی ویژگی name دقیقاً نام سازنده است؛ و پیام از argument گرفتهشده است. برای مثال:
<span class="token keyword">let</span> error <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">"Things happen o_O"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">alert</span><span class="token punctuation">(</span>error<span class="token punctuation">.</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Error</span>
<span class="token function">alert</span><span class="token punctuation">(</span>error<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Things happen o_O</span>
حال بیایید ببینیم JSON.parse چه نوع خطایی ایجاد میکند:
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span><span class="token string">"{ bad json o_O }"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">alert</span><span class="token punctuation">(</span>err<span class="token punctuation">.</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// SyntaxError</span>
<span class="token function">alert</span><span class="token punctuation">(</span>err<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Unexpected token b in JSON at position 2</span>
<span class="token punctuation">}</span>
همانطور که میبینیم، این یک SyntaxError است. در این مثال عدم وجود نام یک خطا است، زیرا کاربران باید یک نام داشته باشند. پس بیایید آن را پرتاب کنیم:
<span class="token keyword">let</span> json <span class="token operator">=</span> <span class="token string">'{ "age": 30 }'</span><span class="token punctuation">;</span> <span class="token comment">// incomplete data</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> user <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>json<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// no errors</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>user<span class="token punctuation">.</span>name<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">SyntaxError</span><span class="token punctuation">(</span><span class="token string">"Incomplete data: no name"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// (*)</span>
<span class="token punctuation">}</span>
<span class="token function">alert</span><span class="token punctuation">(</span> user<span class="token punctuation">.</span>name <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">alert</span><span class="token punctuation">(</span> <span class="token string">"JSON Error: "</span> <span class="token operator">+</span> err<span class="token punctuation">.</span>message <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// JSON Error: Incomplete data: no name</span>
<span class="token punctuation">}</span>
در خط (*)، عملگر throw با پیام دادهشده یک SyntaxError ایجاد میکند، به همان روشی که جاوا اسکریپت خود آن را ایجاد میکند. اجرای try فوراً متوقف میشود و جریان کنترل به حالت گیر در میآید. اکنون catch به یک مکان واحد برای رسیدگی به همه خطاها تبدیل شد.
باز انداختن در دستور try…catch…finally
در مثال بالا از دستور try…catch برای رسیدگی به دادههای نادرست استفاده میکنیم؛ اما آیا ممکن است خطای غیرمنتظره دیگری در بلوک try رخ دهد؟ مثلاً یک خطای برنامهنویسی (متغیر تعریفنشده است) یا چیز دیگری. مثلاً:
<span class="token keyword">et</span> json <span class="token operator">=</span> <span class="token string">'{ "age": 30 }'</span><span class="token punctuation">;</span> <span class="token comment">// incomplete data</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
user <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>json<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// forgot to put "let" before user</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"JSON Error: "</span> <span class="token operator">+</span> err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// JSON Error: ReferenceError: user is not defined</span>
<span class="token comment">// (no JSON Error actually)</span>
<span class="token punctuation">}</span>
در این مقاله، try…catch برای دریافت خطاهای “دادههای نادرست” قرار دادهشده است اما ممکن است هر خطای دیگری نیز رخ دهد. به دلیل ماهیت خود، catch همه خطاها را از طریق try دریافت میکند. در اینجا یک خطای غیرمنتظره دریافت میکند، اما همچنان همان پیام “خطای JSON” را نشان میدهد. این اشتباه است و همچنین اشکالزدایی کد را دشوارتر میکند.
- برای جلوگیری از چنین مشکلاتی، میتوانیم از تکنیک rethrow در جاوا اسکریپت استفاده کنیم. یک قانون ساده برای آن وجود دارد:
- Catch باید فقط خطاهایی را که میداند پردازش کند و بقیه خطاها را rethrow بازگردانی کند.
تکنیک rethrow را میتوان با جزئیات بیشتر به شرح زیر توضیح داد:
- Catch همه خطاها را دریافت میکند.
- در بلوک catch (err) شیء خطا err را تحلیل میکنیم.
معمولاً میتوانیم نوع خطا را با استفاده از عملگر instanceof بررسی کنیم:
همچنین میتوانیم نام کلاس خطا را از ویژگی err.name دریافت کنیم. همه خطاهای بومی آن را دارند. گزینه دیگر خواندن err.constructor.name است.
در کد زیر، از rethrowing استفاده میکنیم تا catch فقط SyntaxError را کنترل کند:
<span class="token keyword">let</span> json <span class="token operator">=</span> <span class="token string">'{ "age": 30 }'</span><span class="token punctuation">;</span> <span class="token comment">// incomplete data</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> user <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>json<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>user<span class="token punctuation">.</span>name<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">SyntaxError</span><span class="token punctuation">(</span><span class="token string">"Incomplete data: no name"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token function">blabla</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// unexpected error</span>
<span class="token function">alert</span><span class="token punctuation">(</span> user<span class="token punctuation">.</span>name <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>err <span class="token keyword">instanceof</span> <span class="token class-name">SyntaxError</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">alert</span><span class="token punctuation">(</span> <span class="token string">"JSON Error: "</span> <span class="token operator">+</span> err<span class="token punctuation">.</span>message <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
<span class="token keyword">throw</span> err<span class="token punctuation">;</span> <span class="token comment">// rethrow (*)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
خطای پرتاب روی خط (*) از داخل بلوک catch از دستور try…catch خارج میشود و میتواند توسط یک ساختار try…catch بیرونی (در صورت وجود) شناسایی شود یا اسکریپت را از بین ببرد.
بنابراین بلوک catch درواقع فقط خطاهایی را کنترل میکند که میداند چگونه با آنها برخورد کند و سایر خطاها را نادیده میگیرد. مثال زیر نشان میدهد که چگونه چنین خطاهایی را میتوان با یک سطح دیگر از دستور try…catch در جاوا اسکریپت گرفت:
<span class="token keyword">function</span> <span class="token function">readData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> json <span class="token operator">=</span> <span class="token string">'{ "age": 30 }'</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token function">blabla</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// error!</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token punctuation">(</span>err <span class="token keyword">instanceof</span> <span class="token class-name">SyntaxError</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">throw</span> err<span class="token punctuation">;</span> <span class="token comment">// rethrow (don't know how to deal with it)</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token function">readData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">alert</span><span class="token punctuation">(</span> <span class="token string">"External catch got: "</span> <span class="token operator">+</span> err <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// caught it!</span>
<span class="token punctuation">}</span>
در اینجا readData فقط میداند که چگونه SyntaxError را مدیریت کند، درحالیکه دستور try…catch در جاوا اسکریپت میداند که چگونه همهچیز را مدیریت کند.
دستور try…catch…finally در جاوا اسکریپت
ساختار دستور try…catch یک بند کد دیگر دارد و آن هم بند finally است. اگر وجود داشته باشد، در همه موارد اجرا میشود:
- پس از try، اگر خطایی وجود نداشت
- پس از catch، در صورت وجود خطا.
سینتکس دستور try…catch…finally در جاوا اسکریپت بهصورت زیر است.
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token operator">...</span> <span class="token keyword">try</span> to execute the code <span class="token operator">...</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token operator">...</span> handle errors <span class="token operator">...</span>
<span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
<span class="token operator">...</span> execute always <span class="token operator">...</span>
<span class="token punctuation">}</span>
یک نمونه کد دیگر از دستور try…catch…finally در جاوا اسکریپت:
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token function">alert</span><span class="token punctuation">(</span> <span class="token string">'try'</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">confirm</span><span class="token punctuation">(</span><span class="token string">'Make an error?'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token constant">BAD_CODE</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">alert</span><span class="token punctuation">(</span> <span class="token string">'catch'</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
<span class="token function">alert</span><span class="token punctuation">(</span> <span class="token string">'finally'</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
این کد دو راه برای اجرا دارد:
- اگر ارور وجود داشته باشد، اجرای دستور try…catch…finally انجم میپذیرد.
- اگر خطا وجود نداشته باشد، try -> finally اجرا میشود.
بند آخر اغلب زمانی استفاده میشود که ما شروع به انجام کاری میکنیم و میخواهیم آن را درهرصورت از آن خروجی بگیریم.
بهعنوانمثال، ما میخواهیم مدتزمانی را که تابع اعداد فیبوناچی fib(n) طول میکشد را اندازهگیری کنیم. طبیعتاً میتوانیم اندازهگیری را قبل از اجرا شروع کنیم و بعدازآن تمام کنیم؛ اما اگر در حین فراخوانی تابع خطایی رخ دهد، چه؟ بهطور خاص، پیادهسازی fib(n) در کد زیر یک خطا برای اعداد منفی یا غیر صحیح برمیگرداند.
بند آخر مکانی عالی برای پایان دادن به اندازهگیریها بدون توجه به هر چیزی است. درنهایت در اینجا تضمین میکند که زمان در هر دو موقعیت بهدرستی اندازهگیری میشود، در صورت اجرای موفقیتآمیز fib و در صورت بروز خطا در آن:
میتوانید با اجرای کد با واردکردن عدد 35 در اعلان، آن را بررسی کنید. بهطورمعمول و درنهایت پس از امتحان اجرا میشود. همچنین اگر عدد 1- را وارد کنید خطای فوری رخ میدهد و اجرا 0 میلیثانیه طول میکشد. هر دو اندازهگیری بهدرستی انجام میشود.
پیشنهاد مطالعه: آموزش Object در جاوا اسکریپت به زبان ساده + مثال عملی
finally and return
بند finally برای هر خروجی از دستور try…catch به کار میرود که شامل بازگشت صریح میشود. در مثال زیر، یک return در try وجود دارد. در این حالت، درنهایت درست قبل از بازگشت کنترل به کد بیرونی اجرا میشود.
<span class="token keyword">function</span> <span class="token function">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">/* ... */</span>
<span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
<span class="token function">alert</span><span class="token punctuation">(</span> <span class="token string">'finally'</span> <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token function">alert</span><span class="token punctuation">(</span> <span class="token function">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// first works alert from finally, and then this one</span>
دستور try…finally در جاوا اسکریپت
ساختار try…finally، بدون بند catch نیز میتواند کاربرد داشته باشد. زمانی که نمیخواهیم خطاها را در اینجا مدیریت کنیم و آن را اعمال میکنیم، اما میخواهیم مطمئن باشیم که فرآیندهایی که شروع کردهایم خروجی میدهند از دستور try…finally استفاده میکنیم.
<span class="token keyword">function</span> <span class="token function">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// start doing something that needs completion (like measurements)</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token comment">// ...</span>
<span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
<span class="token comment">// complete that thing even if all dies</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
کلام پایانی
ساختار دستور try…catch در جاوا اسکریپت امکان رسیدگی به خطاهای زمان اجرا را فراهم میکند. این به معنای واقعی کلمه اجازه میدهد تا کد را امتحان کنیم و خطاهای موجود در آن را بیابیم.
سینتکس دستور try…catch…finally در جاوا اسکریپت بهصورت زیر است:
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token comment">// run this code</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// if an error happened, then jump here</span>
<span class="token comment">// err is the error object</span>
<span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
<span class="token comment">// do in any case after try/catch</span>
<span class="token punctuation">}</span>
ممکن است بخش catch وجود نداشته باشد یا بخش finally وجود نداشته باشد. در این صورت دستور try…catch و دستور try…finally کاربرد خواهند داشت.
آموزش جاوا اسکریپت با مکتب خونه
بخش بزرگی از آموزشهای مکتب خونه را دورههای برنامهنویسی تشکیل میدهند. جاوا اسکریپت یک زبان برنامهنویسی برای فرانتاند است که در سالهای اخیر قابلیت برنامهنویسی برای بکاند را نیز پشتیبانی میکند؛ با یادگیری این زبان میتوانید به عنوان برنامهنویس فولاستک فعالیت کنید. پیشنهاد میکنیم برای یادگیری این مهارت حتماً از دوره های آموزش جاوا اسکریپت و آموزش برنامه نویسی مکتب خونه بازدید فرمایید.