เคยมีคำสั่ง catch ที่ว่างเปล่าหรือไม่?


58

ฉันคิดเกี่ยวกับมันและไม่สามารถมากับตัวอย่าง ทำไมบางคนถึงอยากจะมีข้อยกเว้นและไม่ทำอะไรเลย คุณยกตัวอย่างได้ไหม อาจเป็นเพียงบางสิ่งที่ไม่ควรทำ


ในที่สุดแล้วเรื่องอะไรล่ะ?
Chris

2
btw - ถูกถามเมื่อ SO ปีที่แล้ว: stackoverflow.com/questions/1234343//
warren

17
อย่างน้อยก็ควรมีความคิดเห็นว่าทำไมมันว่างเปล่า
peterchen

คำตอบ:


77

ฉันทำมันตลอดเวลากับสิ่งต่าง ๆ เช่นข้อผิดพลาดในการแปลงใน D:

import std.conv, std.stdio, std.exception;

void main(string[] args) {  
    enforce(args.length > 1, "Usage:  foo.exe filename");

    double[] nums;

    // Process a text file with one number per line into an array of doubles,
    // ignoring any malformed lines.
    foreach(line; File(args[1]).byLine()) {
        try {
            nums ~= to!double(line);
        } catch(ConvError) {
            // Ignore malformed lines.
        }
    }

    // Do stuff with nums.
}

ที่กล่าวว่าฉันคิดว่าบล็อกทั้งหมดควรมีบางสิ่งบางอย่างในนั้นแม้ว่าสิ่งนั้นเป็นเพียงความคิดเห็นอธิบายว่าทำไมคุณไม่สนใจข้อยกเว้น

แก้ไข: ฉันต้องการเน้นว่าหากคุณจะทำสิ่งนี้คุณควรระวังที่จะรับเฉพาะข้อยกเว้นเฉพาะที่คุณต้องการเพิกเฉย การทำสิ่งเก่า ๆcatch {}นั้นเป็นเรื่องที่ไม่ดี


15
+1 สำหรับความคิดเห็นคำอธิบาย
Michael K

IDEs บางตัวอนุญาตให้คุณระบุว่าชื่อเฉพาะสำหรับข้อยกเว้น (โดยปกติคือ "เพิกเฉย") บ่งชี้ว่าคุณเพิกเฉยโดยไม่ตั้งใจซึ่งจะยับยั้งคำเตือนที่จะแสดงเป็นอย่างอื่น สิ่งนี้เกิดขึ้นที่ความคิดเห็น
Alex Feinman

ฉันไม่คุ้นเคย D แต่ฉันคิดว่ามันเป็นไปได้ที่จะทำอะไรบางอย่างเช่นบูลบูล TryParse (สายสตริงออกเป็นสองเท่า valToParse) ซึ่งอาจสะอาดกว่า
ysolik

4
ว้าวคนที่ใช้ D! :-P
James McNellis

4
Like @Michael พูดว่า - มันค่อนข้างจะว่างเปล่าเพราะคุณมีความคิดเห็นที่นั่น มันควรจะมีความรับผิดชอบที่จะเพิ่มความคิดเห็น "จับนี้ว่างไว้โดยเจตนา" หากไม่มีคำสั่ง
STW

50

ตัวอย่างหนึ่งที่ฉันคิดว่าก็โอเคที่จะกลืนข้อยกเว้นโดยไม่ทำอะไรเลยแม้แต่การบันทึกข้อยกเว้นอยู่ภายในรหัสการบันทึกเอง

หากคุณพยายามที่จะบันทึกบางสิ่งบางอย่างและได้รับการยกเว้นมีไม่มากที่คุณสามารถทำได้:

  • คุณไม่สามารถบันทึกได้แน่นอน;
  • คุณอาจสามารถย้อนกลับไปที่กลไกการบันทึกการสำรอง แต่แอพพลิเคชั่นส่วนใหญ่นั้นไม่ซับซ้อนและสำหรับผู้ที่มีความซับซ้อนเพียงพอปัญหาการออกแบบเดียวกันจะเกิดขึ้นกับกลไกการบันทึกการสำรอง
  • ความล้มเหลวอย่างรวดเร็ว - จะเป็นวิธีที่รุนแรงเกินไปสำหรับการใช้งานส่วนใหญ่
  • การโยนข้อยกเว้นจะทำได้ดีเพียงเล็กน้อยเพราะจะจบลงด้วยการจับคำสั่งสแต็กที่เกือบจะแน่ใจว่าพยายามที่จะเข้าสู่ระบบ ...

นั่นทำให้คุณมีตัวเลือก "ความชั่วร้ายน้อยที่สุด" ในการกลืนมันอย่างเงียบ ๆ ทำให้แอปพลิเคชันสามารถทำงานหลักได้อย่างต่อเนื่อง แต่ลดความสามารถในการแก้ไขปัญหา


10
จุดที่ดี การดีบักรหัสการดีบักเป็นสิ่งที่ท้าทายเสมอ
DevSolo

7
นี่เป็นล้านครั้ง โดยเฉพาะอย่างยิ่งเมื่อคุณพิจารณาว่าหากคุณเข้าสู่ระบบคุณอาจอยู่ในสถานะที่แย่ คุณอาจจำไม่ได้อาจจะล้มเหลวหรืออาจเป็นอะไรก็ได้ ณ จุดนี้เมื่อคุณบันทึกข้อผิดพลาดและที่ล้มเหลวสิ่งเดียวที่ต้องรับผิดชอบคือไม่มีอะไร คุณไม่รับประกันว่าสิ่งที่คุณพยายามจะไม่ทำให้แย่ลง
GWLlosa

จุดที่ดี ในรหัสบันทึกของฉันฉันต้องการเพิ่ม InnerMessage สำหรับข้อยกเว้น หลายครั้งที่นี่เป็นโมฆะดังนั้นการพยายามเพิ่มมันจะทำให้การบันทึกเป็นระเบิด
Tangurena

@ Tangurena ถ้ามันเป็นโมฆะแล้วก็จัดการไม่ได้ ใน C # ฉันมักจะปกป้องสิ่งต่าง ๆ โดย? "";
Loren Pechtel

8

หากมีข้อผิดพลาดเกิดขึ้นจากการดำเนินการที่เป็นทางเลือกอย่างไรก็ตามอาจไม่มีอะไรต้องทำ อาจไม่มีประโยชน์ในการบันทึก ในกรณีนี้คุณอาจต้องการจับและไม่ทำอะไรเลย

หากคุณกำลังทำสิ่งนี้รวมถึงความคิดเห็น แสดงความคิดเห็นทุกสิ่งที่ดูเหมือนเป็นข้อบกพร่องเสมอ (การผิดพลาดในswitchคำสั่งcatchบล็อกว่างเปล่าการกำหนดเงื่อนไข)

คุณอาจยืนยันว่านี่ไม่ใช่การใช้ข้อยกเว้นที่เหมาะสม แต่เป็นคำถามอื่น


6

catchบล็อกเปล่าเป็นกลิ่นรหัสในภาษาส่วนใหญ่ แนวคิดหลักคือการใช้ข้อยกเว้นสำหรับสถานการณ์พิเศษและไม่ใช้สำหรับการควบคุมเชิงตรรกะ ข้อยกเว้นทั้งหมดจะต้องได้รับการจัดการที่ไหนสักแห่ง

เป็นผลมาจากการใช้วิธีการนี้เมื่อคุณตั้งโปรแกรมเลเยอร์แอปพลิเคชันหนึ่งโดยเฉพาะคุณมีหลายทางเลือก:

  • ไม่ทำอะไรเกี่ยวกับข้อยกเว้น มันจะถูกจับและจัดการโดยเลเยอร์อื่น
  • จับมันและทำการแก้ไข
  • จับมันทำอะไรสักอย่าง แต่ให้โยนอีกชั้นหนึ่งเพื่อจัดการ

สิ่งนี้ไม่ได้ออกจากห้องเพื่อcatchบล็อกที่ว่างเปล่า

แก้ไขเพื่อเพิ่ม : สมมติว่าคุณกำลังเขียนโปรแกรมในภาษาที่การโยนข้อยกเว้นเป็นวิธีปกติในการควบคุมตรรกะของโปรแกรม (หนึ่งในตัวเลือกgoto) จากนั้นcatchบล็อกว่างเปล่าในโปรแกรมที่เขียนในภาษานี้จะคล้ายกับelseบล็อกว่างเปล่าในภาษาดั้งเดิม (หรือไม่มีelseบล็อกเลย) อย่างไรก็ตามฉันเชื่อว่านี่ไม่ใช่รูปแบบการเขียนโปรแกรมที่แนะนำโดยชุมชนการพัฒนา C #, Java หรือ C ++


ฉันคิดว่าการใช้ข้อยกเว้นเนื่องจากการควบคุมแบบลอจิกค่อนข้างธรรมดาดังนั้นฉันจึงพบว่าตัวเองว่างเปล่าหรือเกือบจะว่างเปล่าช่วงตึก
whatsisname

+1 สำหรับการรับรู้ว่าบล็อก catch ที่ว่างสามารถระบุการใช้ข้อยกเว้นสำหรับการควบคุมการไหล
John M Gant

การใช้ข้อยกเว้นสำหรับลอจิกการเขียนโปรแกรมนั้นโดยทั่วไปถือว่าเป็นการฝึกที่ไม่ดี แต่น่าแปลกใจ (ข้อโต้แย้งเดิมของฉันกับข้อยกเว้น) ข้อยกเว้นไม่ได้รับผลกระทบที่เห็นได้ชัดเจน ดูcodeproject.com/KB/exception/ExceptionPerformance.aspx
Evan Plaice

6

ในบางกรณี Java ต้องการให้คุณจัดการกับข้อยกเว้นที่อาจเกิดขึ้นได้ พิจารณารหัสนี้:

try {
   bytes[] hw = "Hello World".getBytes("UTF-8");
}
catch(UnsupportedCodingException e) {
}

ทุกการใช้งานของแพลตฟอร์ม Java จำเป็นต้องมีการสนับสนุนชุดอักขระมาตรฐานต่อไปนี้

...

UTF-8

หากไม่มีการทำลายแพลตฟอร์ม Java ของคุณก็ไม่มีทางที่จะทำให้เกิดข้อยกเว้นนี้ได้ ดังนั้นทำไมต้องจัดการกับมัน แต่คุณไม่สามารถเลิกลองประโยคได้


1
ในกรณีเช่นนี้ฉันจะถูกล่อลวงให้เพิ่มthrow new Error(e)เพียงเพื่อให้แน่ใจว่าฉันจะไม่พลาดอะไรเลย (หรือรายงานแพลตฟอร์มที่เสียจริง)
Halle Knast

@ HalleKnast ใช่ นี้ได้รับการกล่าวถึงในรายละเอียดทั้งหมดที่นี่: softwareengineering.stackexchange.com/questions/122233/ …
281377

5

ตามกฎทั่วไปไม่มี คุณต้องการที่จะโยนข้อยกเว้นขึ้นสแต็กหรือบันทึกสิ่งที่เกิดขึ้น

อย่างไรก็ตามฉันมักจะทำเช่นนี้เมื่อฉันแยกวิเคราะห์สตริงและแปลงเป็นตัวเลข (โดยเฉพาะในการทำแผนที่โครงการที่มีการใช้งานครั้งเดียวและทิ้งความหลากหลาย)

boolean isNonZeroNumber = false;

try {
   if(StringUtils.isNotBlank(s) && new BigDecimal(s).compareTo(BigDecimal.ZERO) != 0) {
     b = true;
   }
} catch(NumberFormatException e) {
//swallow this exception; b stays false.
}

return b;

3

ในบางกรณีข้อยกเว้นนั้นไม่พิเศษเลย ในความเป็นจริงก็คาดว่า ลองพิจารณาตัวอย่างนี้:

    /* Check if the process is still alive; exitValue() throws an exception if it is */
    try {
        p.exitValue();
        processPool.remove(p);
    }
    catch (IllegalThreadStateException e) { /* expected behaviour */ }

เนื่องจากไม่มี isAlive () วิธีการใน java.lang.Process () เกี่ยวกับวิธีเดียวที่จะตรวจสอบว่ามันยังมีชีวิตอยู่คือการเรียก exitValue () ซึ่งจะโยน IllegalThreadStateException หากกระบวนการยังคงทำงานอยู่


2

จากประสบการณ์ที่ต่ำต้อยของฉันสิ่งนี้ไม่ค่อยดี ไมล์สะสมของคุณอาจแตกต่างกัน

เกือบทุกครั้งที่ฉันเห็นสิ่งนี้ในฐานรหัสของเรามันเป็นเพราะฉันได้ติดตามข้อผิดพลาดที่ข้อยกเว้นการกินถูกซ่อนไว้ หากต้องการใส่วิธีอื่นโดยไม่ให้รหัสใด ๆ แอปพลิเคชันไม่มีวิธีระบุข้อผิดพลาดหรือดำเนินการกระทำอื่น

บางครั้งที่เลเยอร์ API คุณอาจไม่ต้องการหรือไม่สามารถให้ข้อยกเว้นผ่านมาดังนั้นในกรณีนี้ฉันมักจะลองและจับคนทั่วไปที่สุดแล้วบันทึกสิ่งเหล่านั้น อีกครั้งอย่างน้อยก็ให้โอกาสในการดีบัก / วินิจฉัย

โดยปกติแล้วถ้ามันจะต้องเป็นที่ว่างเปล่าอย่างน้อยฉันทำคือการใส่การยืนยันของบางชนิดดังนั้นอย่างน้อยสิ่งที่เกิดขึ้นในช่วงการแก้ปัญหา ที่กล่าวว่าถ้าฉันไม่สามารถจัดการได้ฉันมักจะละเว้นพวกเขาอย่างสมบูรณ์


2

IMO มีที่เดียวที่คำสั่ง catch ว่างเปล่าตกลง ในกรณีทดสอบที่คุณคาดว่าจะมีข้อยกเว้น:

try
{
   DoSomething(); //This should throw exception if everything works well
   Assert.Fail('Expected exception was not thrown');
}
catch(<whatever exception>)
{
    //Expected to get here
}

+1 ฉันเกลียดที่ฉันทำเช่นนี้ แต่การทำงานใน JUnit
พะยอม

@sal: แล้ว @Test (คาดว่า = Exception.class) คืออะไร
ysolik

@ysolik, นิสัยไม่ดี
พะยอม

1
@sal: ทำไมเป็นนิสัยที่ไม่ดี?
Adam Lear

ummmm มีวิธีการทำเช่นนี้กับกรอบการทดสอบหน่วย อดีต NUnit มีบางกรณีที่การทดสอบว่าสิ่งที่คาดการณ์ไม่ได้อาจมีประโยชน์ แม้ว่าฉันจะไม่ทำในรหัสการผลิต
Evan Plaice

2

ฉันเชื่อว่ามีบางกรณีที่มีเหตุผลที่จะมีประโยค catch เปล่า - นี่เป็นกรณีเมื่อคุณต้องการให้โค้ดทำงานต่อไปหากการดำเนินการบางอย่างล้มเหลว อย่างไรก็ตามฉันคิดว่ารูปแบบนี้สามารถใช้งานได้ง่ายเกินไปดังนั้นควรตรวจสอบการใช้แต่ละครั้งอย่างใกล้ชิดเพื่อให้แน่ใจว่าไม่มีวิธีที่ดีกว่าในการจัดการกับมัน โดยเฉพาะอย่างยิ่งสิ่งนี้ไม่ควรกระทำหากออกจากโปรแกรมในสถานะที่ไม่สอดคล้องกันหรืออาจทำให้บางส่วนของรหัสล้มเหลวในภายหลัง


1

ฉันไม่เชื่อว่าจะไม่มีการแจ้งเตือนในระดับหนึ่งเมื่อมีข้อยกเว้นเกิดขึ้น - หนึ่งในเป้าหมายของการเขียนโปรแกรมไม่ควรปรับปรุงรหัสหรือไม่ หากมีข้อยกเว้นเกิดขึ้น 10% ของเวลาและคุณไม่เคยรู้เลยว่าข้อยกเว้นนั้นจะเป็นเรื่องเลวร้ายหรือแย่กว่านั้นเสมอ

อย่างไรก็ตามฉันเห็นอีกด้านหนึ่งว่าถ้าข้อยกเว้นไม่มีอันตรายใด ๆ ในการประมวลผลของรหัสแล้วทำไมผู้ใช้ถึงเปิดเผยมัน วิธีแก้ปัญหาที่ฉันนำมาใช้มักจะมีการบันทึกโดยคลาส logger ของฉัน (ที่อยู่ในทุกชั้นเดียวที่ฉันเคยเขียนในที่ทำงาน)

หากเป็นข้อยกเว้นที่ใจดีฉันจะโทรไปที่. Logger's () วิธีการ; มิฉะนั้น Logger.Error () (และ (อาจ)) การโยน

try
{
   doWork();
}
catch(BenignException x)
{
  _log.Debug("Error doing work: " + x.Message);
}

โดยวิธีการในการใช้งานของคนตัดไม้ของฉันการโทรไปที่วิธี. Debug () จะบันทึกเฉพาะถ้าฉัน App.Config ไฟล์ของฉันระบุว่าระดับการบันทึกการดำเนินการของโปรแกรมอยู่ในโหมด Debug


จะเกิดอะไรขึ้นถ้า _log.Debug ส่งข้อยกเว้น (ด้วยเหตุผลใดก็ตาม)
JohnL

จากนั้น. Debug () กินข้อยกเว้นและฉันไม่เคยรู้เลย แต่ฉันรู้สึกมั่นใจมากขึ้นเกี่ยวกับคนตัดไม้ของฉันมากกว่าที่ฉันรู้สึกเกี่ยวกับรหัสที่มักจะโยนข้อยกเว้น หากฉันกังวลเกี่ยวกับสิ่งนั้นฉันคิดว่าฉันสามารถใช้รูปแบบบางอย่างที่จับตามองการเข้าสู่บล็อก catch และบันทึกในภายหลัง ไม่ว่าในกรณีใด - จุดที่ใช้
Tim Claason

1

การตรวจสอบการมีอยู่เป็นกรณีการใช้ที่ดี:

// If an exception happens, it doesn't matter. Log the initial value or the new value

function logId(person) {
    let id = 'No ID';
    try {
        id = person.data.id;
    } catch {}
    console.log(id);
}

อีกกรณีหนึ่งคือเมื่อมีการใช้finallyข้อ:

 function getter(obj){}

 function objChecker()
   {
   try
     {
     /* Check argument length and constructor type */
     if (getter.length === 1 && getter.constructor === Function)
       {
       console.log("Correct implementation");
       return true;
       }
     else
       {
       console.log("Wrong implementation");
       return false;
       }
     }
   catch(e)
     {
     }
   finally
     {
     console.log(JSON.stringify(getter))
     }
   }

 // Test the override of the getter method 
 getter = getter;
 objChecker();
 getter = [];
 objChecker();
 getter = {};
 objChecker();
 getter = RegExp;
 objChecker();
 getter = Function;
 objChecker();

มีข้อเสนอเพื่อให้ละเว้นการจับการจับใน ECMAScript ซึ่งเกี่ยวข้องกับกรณีนี้และการใช้งานที่คล้ายกัน

อ้างอิง


อีกตัวอย่าง: ใน nodejs วิธีการ fs.exists (ซึ่งผลตอบแทนจริงหรือเท็จ) เลิกใช้แล้ว ( nodejs.org/dist/latest-v10.x/docs/api/ ...... ) เพื่อสนับสนุน fs.access ซึ่งส่งข้อยกเว้นใน กรณีไม่มีไฟล์ ถ้าใครอยากทำอะไรก็ต่อเมื่อไฟล์มีอยู่ catch clause นั้นไม่จำเป็นเลย
systemovich

0

ครั้งเดียวที่ฉันต้องการทำบางสิ่งเช่นนี้กับคลาสการบันทึกสำหรับแอปคอนโซล มีตัวจัดการการดักจับโกลบอลระดับบนสุดซึ่งส่งข้อผิดพลาดไปยัง STDOUT บันทึกข้อผิดพลาดไปยังไฟล์จากนั้นปิดแอปด้วยรหัสข้อผิดพลาด> 0

ปัญหาที่เกิดขึ้นคือบางครั้งการบันทึกไฟล์ล้มเหลว สิทธิ์ของไดเรกทอรีทำให้คุณไม่สามารถเขียนไฟล์ได้ไฟล์ดังกล่าวถูกล็อคไว้โดยเฉพาะ หากสิ่งนั้นเกิดขึ้นฉันไม่สามารถจัดการข้อยกเว้นได้ในลักษณะเดียวกับที่ฉันมี (ที่อื่นบันทึกการบันทึกรายละเอียดที่เกี่ยวข้องห่อในประเภทข้อยกเว้นที่ดีกว่า ฯลฯ ) เนื่องจากการบันทึกรายละเอียดข้อยกเว้นทำให้คนตัดไม้ทำงานแบบเดียวกัน พยายามเขียนไฟล์) ซึ่งล้มเหลวแล้ว เมื่อพวกเขาล้มเหลวอีกครั้ง ... คุณจะเห็นว่าฉันกำลังจะไปไหน มันเข้าสู่วงวนไม่ จำกัด

หากคุณวางบล็อกลอง {} บางส่วนคุณสามารถจบลงด้วยข้อยกเว้นที่ปรากฏในกล่องข้อความ (ไม่ใช่สิ่งที่คุณต้องการสำหรับแอพ config แบบเงียบ) ดังนั้นในวิธีที่เขียนไปยังล็อกไฟล์นั้นฉันมีตัวจัดการ catch ว่างเปล่า การทำเช่นนี้ไม่ได้เป็นการฝังข้อผิดพลาดเนื่องจากคุณยังได้รับรหัสข้อผิดพลาด> 0 แต่มันจะหยุดการวนซ้ำไม่สิ้นสุดและอนุญาตให้แอปออกไปอย่างสง่างาม

มีความคิดเห็นแน่นอนอธิบายว่าทำไมมันว่างเปล่า

(ฉันจะโพสต์ก่อนหน้านี้ฉันแค่กลัวว่าจะโดนเผาจนลืมเลือนเพราะฉันไม่ใช่คนเดียว แต่ ... )


0

มันก็โอเคในสถานการณ์ที่ต้องดำเนินการบางอย่างไม่ว่าอะไรจะเกิดขึ้นกับชิ้นส่วนที่สำคัญที่สุดในตอนท้าย

ตัวอย่างเช่น. ในการสื่อสารการควบคุมการเคลื่อนไหวของโฮสต์กับตัวควบคุม ในสถานการณ์ฉุกเฉินมีขั้นตอนการเตรียมการจำนวนหนึ่งเพื่อยกเลิกการเคลื่อนไหวหยุดการสร้างเส้นทางลดความเร็วมอเตอร์เปิดใช้งานการหยุดพักปิดการใช้งานเครื่องขยายเสียงและหลังจากนี้คุณจะต้องฆ่าพลังรถบัส ทั้งหมดจะต้องเกิดขึ้นตามลำดับและหากขั้นตอนใดขั้นตอนหนึ่งล้มเหลวต้องดำเนินการขั้นตอนที่เหลือต่อไปแม้ว่าจะมีความเสี่ยงที่จะเกิดความเสียหายกับฮาร์ดแวร์ พูดแม้ว่าข้างต้นล้มเหลวพลังรถบัสฆ่าจะต้องเกิดขึ้นต่อไป


นั่นไม่ได้หมายความว่าคุณจะไม่ทำอะไรเลยเพียงแค่สิ่งที่คุณไม่ได้ยกเลิกการไหล จับข้อยกเว้นของคุณบันทึกไว้ในหน่วยความจำ (ไม่มีความล่าช้าในการเขียนดิสก์) จากนั้นทำลายพลังงานในคำสั่งสุดท้าย จากนั้นทำสิ่งที่คุณต้องการด้วยข้อมูลที่บันทึกไว้
Loren Pechtel

0

การปิดทรัพยากรระบบอย่างสง่างามเพื่อกู้คืนจากข้อผิดพลาด

ตัวอย่างเช่น หากคุณกำลังใช้บริการในพื้นหลังที่ไม่ได้ให้ข้อเสนอแนะให้กับผู้ใช้ที่คุณอาจไม่ต้องการที่จะผลักดันข้อบ่งชี้ของข้อผิดพลาดไปยังผู้ใช้ แต่คุณไม่จำเป็นต้องปิดจากทรัพยากรที่ถูกนำมาใช้ในลักษณะที่สง่างาม

try
{
    // execution code here
}
catch(Exception e)
{
    // do nothing here
}
finally
{
    // close db connection
    // close file io resource
    // close memory stream
    // etc...
}

โดยอุดมคติแล้วคุณจะต้องใช้โหมด catch in debug เพื่อตรวจจับข้อผิดพลาดและพิมพ์ลงในคอนโซลหรือไปยังไฟล์บันทึกสำหรับการทดสอบ ในสภาพแวดล้อมการผลิตบริการพื้นหลังโดยทั่วไปคาดว่าจะไม่ขัดจังหวะผู้ใช้เมื่อมีข้อผิดพลาดจะถูกโยนดังนั้นข้อผิดพลาดออกควรจะระงับ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.