xpcall และตัวจัดการข้อความ
ใช้ xpcall ร่วมกับตัวจัดการแบบกำหนดเองเพื่อดูร่องรอยข้อผิดพลาดโดยละเอียด
xpcall และตัวจัดการข้อความ เป็นบทเรียน Lua Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Lua Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Lua Academy มีบทเรียนทั้งหมด 4 บทเรียน
ไวยากรณ์ของ xpcall
xpcall(f, handler, ...) เรียก f พร้อมอาร์กิวเมนต์ ... ในโหมดที่มีการป้องกัน และเมื่อเกิดข้อผิดพลาดจะเรียก handler(errorObject) ค่าที่ตัวจัดการคืนมาจะกลายเป็นค่าที่คืนค่าที่สองของ xpcall ต่างจาก pcall ตรงที่ xpcall เรียกตัวจัดการขณะที่ลำดับการเรียกยังสมบูรณ์
local function handler(err)
return "HANDLED: " .. tostring(err)
end
local ok, msg = xpcall(
function() error("something bad") end,
handler
)
print(ok) -- false
print(msg) -- HANDLED: ...: something badใช้ debug.traceback เป็นตัวจัดการ
ตัวจัดการของ xpcall ที่ใช้กันทั่วไปที่สุดคือ debug.traceback ให้ส่งเป็นตัวจัดการโดยตรง เพราะจะจัดรูปแบบข้อผิดพลาดพร้อมร่องรอยการเรียกทั้งหมด ซึ่งมีประโยชน์อย่างมากต่อการแก้ไขข้อผิดพลาดในระบบจริง
local function level3() error("deep error") end
local function level2() level3() end
local function level1() level2() end
local ok, err = xpcall(level1, debug.traceback)
if not ok then
-- err contains the full stack trace
print(err)
endตัวจัดการแบบกำหนดเองพร้อมบริบท
ตัวจัดการแบบกำหนดเองสามารถเพิ่มบริบทได้ เช่น ประทับเวลา บันทึกลงไฟล์ และแจ้งระบบติดตามตรวจสอบ จากนั้นจึงคืนค่าข้อผิดพลาดที่จัดรูปแบบแล้ว นี่คือรูปแบบมาตรฐานสำหรับการจัดการข้อผิดพลาดของแอปพลิเคชัน Lua ในระบบจริง
local function errorHandler(err)
local trace = debug.traceback(err, 2)
local ts = os.date("%H:%M:%S")
local report = string.format("[%s] ERROR\n%s", ts, trace)
-- Could log to file here
io.stderr:write(report .. "\n")
return report
end
local ok, msg = xpcall(
function()
local t = nil
return t.field -- error!
end,
errorHandler
)
print("ok:", ok)ตัวจัดการต้องไม่เกิดข้อผิดพลาด
หากตัวจัดการข้อความเองยกข้อผิดพลาด Lua จะคืนตัวบ่งชี้ข้อผิดพลาดโดยไม่เรียกตัวจัดการซ้ำ ควรเขียนตัวจัดการให้รับมือได้ทุกกรณีเสมอ ห้ามใช้ IO ที่อาจล้มเหลวและห้ามเข้าถึงดัชนีของค่า nil
local function safeHandler(err)
-- Keep handler simple and safe
local ok, trace = pcall(debug.traceback, err, 2)
if ok then return trace
else return tostring(err) .. " (traceback failed)"
end
end
local ok, msg = xpcall(
function() error({complex="error table"}) end,
safeHandler
)
print(ok, type(msg))ใช้ xpcall กับลูปหลัก
ในโปรแกรมที่ทำงานต่อเนื่องเป็นเวลานาน เช่น เซิร์ฟเวอร์หรือลูปเกม ให้ห่อฟังก์ชันหลักด้วย xpcall เพื่อดักจับและบันทึกข้อผิดพลาดที่ไม่ได้จัดการโดยไม่ทำให้โปรแกรมหยุดทำงาน จากนั้นลูปหลักจะตัดสินใจได้ว่าจะเริ่มใหม่หรือจบการทำงาน
local function mainApp()
-- simulate work
for i = 1, 3 do
print("Tick", i)
if i == 2 then error("transient error") end
end
end
local function handler(e)
return debug.traceback("App error: "..tostring(e), 2)
end
local ok, err = xpcall(mainApp, handler)
if not ok then
print("Application crashed:\n" .. err)
endการรายงานข้อผิดพลาดแบบมีโครงสร้าง
ผสาน xpcall เข้ากับออบเจ็กต์ข้อผิดพลาดแบบมีโครงสร้างและตัวจัดการที่มีข้อมูลครบถ้วน เพื่อสร้างรายงานข้อผิดพลาดที่ละเอียดและนำไปดำเนินการต่อได้ สำหรับการแก้ไขข้อผิดพลาดหรือแผงติดตามตรวจสอบ
local function handler(err)
local info = {
error = tostring(err),
time = os.date("!%Y-%m-%dT%H:%M:%SZ"),
trace = debug.traceback(nil, 2),
}
return info
end
local ok, report = xpcall(
function() error({code=500, msg="internal error"}) end,
handler
)
if not ok then
print("Time:", report.time)
print("Error:", report.error)
-- print("Trace:", report.trace)
endใช้ xpcall กับโครูทีน
ภายในโครูทีน pcall ทำงานตามปกติ หากต้องการร่องรอยการเรียกจากข้อผิดพลาดภายในโครูทีน ให้ห่อเนื้อหาของโครูทีนด้วย xpcall ตัวจัดการจะทำงานภายในบริบทลำดับการเรียกของโครูทีน
local function co_body()
error("error inside coroutine")
end
local co = coroutine.create(function()
local ok, err = xpcall(co_body, debug.traceback)
if not ok then
print("Caught in coroutine:", err:match("([^\n]+)"))
end
end)
coroutine.resume(co)การเพิ่มข้อมูลให้ออบเจ็กต์ข้อผิดพลาด
ตัวจัดการสามารถเปลี่ยนข้อผิดพลาดแบบสตริงธรรมดาให้เป็นออบเจ็กต์ที่มีข้อมูลครบถ้วน หรือเพิ่มข้อมูลให้ออบเจ็กต์ที่มีข้อมูลอยู่แล้วได้ วิธีนี้ทำให้โค้ดระดับล่างโยนข้อผิดพลาดอย่างง่าย ขณะที่ตัวจัดการเพิ่มบริบท เช่น รหัสคำขอ เซสชันผู้ใช้ และข้อมูลสภาพแวดล้อม
local requestID = "req-123"
local function handler(err)
if type(err) == "string" then
return {message=err, requestID=requestID, level="error"}
end
err.requestID = requestID
return err
end
local ok, result = xpcall(
function() error("database timeout") end,
handler
)
if not ok then
print(result.message, result.requestID)
-- database timeout req-123
endเปรียบเทียบ pcall กับ xpcall
ใช้ pcall เมื่อคุณต้องการเพียงค่าข้อผิดพลาด ข้อผิดพลาดนั้นคาดหมายได้และจัดการทันที หรือให้ความสำคัญกับความเรียบง่าย ใช้ xpcall เมื่อคุณต้องการร่องรอยการเรียก อยู่ที่ขอบเขตระดับบนสุด หรือต้องการเพิ่มบริบทให้ข้อผิดพลาดทั้งหมด
-- pcall: simple, no overhead
local ok, err = pcall(function()
return 1/0 -- no error in Lua! returns inf
end)
print(ok, err) -- true inf
-- xpcall: adds traceback
local ok2, err2 = xpcall(
function() error("real error") end,
debug.traceback
)
print(ok2) -- false
print(err2:sub(1,40)) -- first line of tracebackค่าที่ตัวจัดการคืน
ไม่ว่าตัวจัดการจะคืนค่าอะไร ค่านั้นจะกลายเป็นค่าที่สองจาก xpcall หากตัวจัดการคืนค่า nil ค่าที่คืนค่าที่สองของ xpcall ก็จะเป็น nil ตัวจัดการที่คืนออบเจ็กต์ข้อผิดพลาดเดิมพร้อมข้อมูลเพิ่มเติมเป็นแนวทางที่ยืดหยุ่นที่สุด
local function enrichedHandler(err)
return {
original = err,
traceback = debug.traceback(nil, 2),
timestamp = os.time(),
}
end
local ok, report = xpcall(
function() error("oops") end,
enrichedHandler
)
if not ok then
print(type(report)) -- table
print(report.original) -- ...: oops
print(report.timestamp > 0) -- true
endตรวจสอบอย่างรวดเร็ว
ข้อได้เปรียบสำคัญของ xpcall เหนือ pcall คืออะไร
ทบทวน: xpcall
สรุป:
xpcall(f, handler, ...)— ตัวจัดการทำงานขณะที่ลำดับการเรียกยังสมบูรณ์- ใช้
debug.tracebackเป็นตัวจัดการเพื่อรับร่องรอยการเรียกทั้งหมด - ตัวจัดการต้องไม่เกิดข้อผิดพลาด ควรเขียนให้เรียบง่าย
- เพิ่มบริบทให้ข้อผิดพลาดภายในตัวจัดการ
- ห่อลูปหลักหรือตัวจัดการเซิร์ฟเวอร์ด้วย xpcall
- ค่าที่ตัวจัดการคืนจะกลายเป็นค่าที่คืนค่าที่สองของ xpcall
คำถามที่พบบ่อย
บทเรียน “xpcall และตัวจัดการข้อความ” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “xpcall และตัวจัดการข้อความ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Lua Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Lua Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “xpcall และตัวจัดการข้อความ”
ใช้ xpcall ร่วมกับตัวจัดการแบบกำหนดเองเพื่อดูร่องรอยข้อผิดพลาดโดยละเอียด คุณปฏิบัติ Lua Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Lua Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Lua Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “xpcall และตัวจัดการข้อความ” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Lua Academy นี้ได้ไหม
ได้ บทเรียน Lua Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ฟังก์ชัน error()
- การเรียกใช้แบบป้องกันด้วย pcall
- xpcall และตัวจัดการข้อความ
- ออบเจกต์ข้อผิดพลาดแบบมีโครงสร้าง