
Kodunuzu yazarken hataların oluşabileceği farklı senaryoları göz önünde bulundurmak önemlidir. Web uygulamanızın ayrılmaz bir parçası olurlar, çünkü ele alınmadan bırakılırsa kaçınılamayan ölümcül senaryolardan (uygulamanızın tamamen çökmesi gibi) kaçınabilirsiniz.
Bu gönderi, hataları kontrol etme ve bunları JavaScript’te işleme konusunda bazı en iyi uygulamaları gözden geçirecektir.
Hatayı Genişletme
Hata işleyicileriniz içinde daha açıklayıcı bir hata sağlamak genellikle yararlıdır. Ve bununla sadece hata mesajınızı daha net yazmaktan bahsetmiyorum. Bahsettiğim şey uzatmak Error
sınıf.
Bunu yaparak özelleştirebilirsiniz name
ve message
hata ayıklama ve buna ihtiyaç duyan özel alıcılar, ayarlayıcılar ve yöntemler eklemek için yararlı olacak özellik:
class BadParametersError extends Error {
name = 'BadParametersError'
constructor(message) {
super(message)
}
get recommendation() {
return this._recommendation
}
set recommendation(recommendation) {
this._recommendation = recommendation
}
}
Bu, özellikle benzer şekilde atan birden çok kod bloğunuz varsa, daha sorunsuz bir hata ayıklama deneyimi sağlayabilir. Kodunuzdaki birden çok senaryo aynı nedenlerle oluşturulduğunda ve bazı ek bağlamlara ihtiyaç duyduğunda, geri dönüp tam olarak neden bir yardımcı program olmadan atıldığını bulmak biraz zor olabilir – hatanın türüne bağlı olarak elbette.
Bunun yararlı hale geldiği bir senaryoyu gözden geçirelim.
Diyelim ki çözümleyici işlevlerin bir listesini alan bir işleviniz var. İşlev bir argüman alır ve çalıştığında çözümleyiciler arasında döngü yapar ve argümanı her işleve iletir. Bir işlev bir sonuç döndürürse, döngüyü durdurur ve sonucu döndürür:
function composeResolvers(...resolvers) {
return (args) => {
let result
for (let index = 0; index < resolvers.length; index++) {
const resolve = resolvers[index]
result = resolve(args)
if (result) {
break
}
}
return result
}
}
Şimdi, kullanıcıyı yaşlarına göre bir gruba atamadan önce doğduğu yılı girmesini isteyen bir sayfa oluşturduğumuzu varsayalım:
import composeResolvers from '../composeResolvers'
const resolvers = []
const someResolverFn = (userInput) => {
if (userInput > 2002) {
return 'NewKidsOnTheBlock'
}
return 'OldEnoughToVote'
}
if (/chrome/i.test(navigator.userAgent)) {
resolvers.push(someResolverFn)
}
const resolve = composeResolvers(...resolvers)
window.addEventListener('load', () => {
const userInput = window.prompt('What year was your computer created?')
const result = resolve(userInput)
window.alert(`We recommend that you register for the group: ${result}`)
})
Bu kod kullanıcıya sorar ve tıkladıklarında TAMAMyaşları atanır userInput
ve tarafından üretilen işleve bir argüman olarak gönderilir. composeResolvers
:
Ve bittiğinde çalışır window.alert
kullanıcıya hesaplanan grubu göstermek için:
Bu iyi çalışıyor ama ya kullanıcı değildi chrome tarayıcıyı mı kullanıyorsunuz? Bu, bu satırın çalışmayacağı anlamına gelir:
resolvers.push(someResolverFn)
Bu, utanç verici beklenmeyen bir sonuç üretir:
Bu gibi işlenmemiş hataların önüne bir normal atarak önleyebiliriz. Error
veya daha spesifik olanı kullanabiliriz BadParametersError
:
function composeResolvers(...resolvers) {
if (!resolvers.length) {
const err = new BadParametersError(
'Need at least one function to compose resolvers',
)
err.recommendation =
'Provide a function that takes one argument and returns a value'
throw err
}
return (args) => {
let result
for (let index = 0; index < resolvers.length; index++) {
const resolve = resolvers[index]
result = resolve(args)
if (result) {
break
}
}
return result
}
}
Bu şekilde, bu hatanın kullanıcıya ulaşma şansı çok daha düşüktür ve geliştiricinin hatayı düzeltmesini sağlar:
Birden çok işlev bu stratejiyi kullanıyorsa ve aşağıdaki gibi bir özellik eklenmişse recommended
örneğin, hata ayıklama deneyimi çok daha kolay hale gelir.
Şimdi daha iyi bir savunma mekanizması olan böyle bir şeye yazılabilir:
const resolve = composeResolvers(...resolvers)
window.addEventListener('load', () => {
const userInput = window.prompt('What year was your computer brought to you?')
let result
try {
result = resolve(userInput)
} catch (error) {
if (error instanceof BadParametersError) {
console.error(
`[Error] ${error.message}. Here's a recommendation: ${error.recommendation}`,
)
console.log(error.recommendation)
} else {
return window.alert(
'We are sorry, there was a technical problem. Please come back later',
)
}
}
window.alert(`We recommend that you register for the group: ${result}`)
})
Kullanın TypeError
Hataları genellikle fırlatarak hallederiz Error
. Ancak, fırsat geldiğinde senaryoyu daraltmak için yerleşik JavaScript hataları mevcut olduğunda, sadece onları kullan:
async function fetchDogs(id) {
let result
if (typeof id === 'string') {
result = await api.fetchDogs(id)
} else if (typeof id === 'array') {
result = await Promise.all(id.map((str) => api.fetchDogs(id)))
} else {
throw new TypeError(
'callSomeApi only accepts a string or an array of strings',
)
}
return result
}
const params = { id: 'doggie123' }
let dogs
fetchDogs(params)
.then((dogs) => {
dogs = dogs
})
.catch((err) => {
if (err instanceof TypeError) {
dogs = Promise.resolve(fetchDogs(params.id))
} else {
throw err
}
})
Test yapmak
türetilmiş yararlanarak Error
s testleri, iddialarınızı yapmak için bunları doğrudan kullanabildiğiniz için daha sağlam hale gelir:
import { expect } from 'chai'
import chaiAsPromised from 'chai-as-promised'
import fetchCats from '../fetchCats'
chai.use(chaiAsPromised)
it('should only take in arrays', () => {
expect(fetchCats('abc123')).to.eventually.rejectWith(TypeError)
})
Aşırıya kaçmak
Ne kadar yararlı olduğunu bilmek, özellikle JavaScript’i yeni öğrenmeye başladığınızda, aklınıza gelebilecek her olası senaryo için bir sürü özel hata oluşturmak da cazip hale geliyor. Bu nedenle, küçük ila orta ölçekli bir uygulamanız varsa ve aşağıdaki gibi bir durumla karşılaşırsanız:
class AbortExecuteError extends Error {
name = 'AbortExecuteError'
constructor(message) {
super(message)
}
}
class BadParameters extends Error {
name = 'BadParameters'
constructor(message) {
super(message)
}
}
class TimedOutError extends Error {
name = 'TimedOutError'
constructor(message) {
super(message)
}
}
class ArrayTooLongError extends Error {
name = 'ArrayTooLongError'
constructor(message) {
super(message)
}
}
class UsernameError extends Error {
name = 'UsernameError'
constructor(message) {
super(message)
}
}
O zaman bu yaklaşımı yeniden düşünebilir ve Gerçekten bunu yapmak gerek ya da yapmamak. Çoğu zaman daha net bir hata sağlamak için yeterlidir message
. Özel hatalarla ilgili iddialarda bulunmak, yalnızca bir jeton örneğin zaman aşımına uğramış bir isteği yeniden denemek için:
class TimedOutError extends Error {
name = 'TimedOutError'
retried = 0
constructor(message) {
super(message)
}
set retry(callback) {
this._retry = callback
}
retry(...args) {
this.retried++
return this._retry(...args)
}
}
class ConnectToRoomTimedOutError extends TimedOutError {
name = 'ConnectToRoomTimedOutError'
constructor(message) {
super(message)
}
get token() {
return this._token
}
set token(token) {
this._token = token
}
}
let timeoutRef
async function connect(token) {
if (timeoutRef) clearTimeout(timeoutRef)
timeoutRef = setTimeout(() => {
const err = new ConnectToRoomTimedOutError(
'Did not receive a response from the server',
)
err.retry = connect
err.token = token
throw err
}, 10000)
const room = await api.join(token)
clearTimeout(timeoutRef)
return room
}
}
const joinRoom = () => getToken().then((token) => connect(token))
async function start() {
try {
let room = await joinRoom()
return room
} catch (err) {
if (err instanceof ConnectToRoomTimedOutError) {
try {
room = await err.retry(err.token)
return room
} catch (innerErr) {
throw innerError
}
}
throw err
}
}
start()
.then((room) => {
console.log(`Received room, oh yea!`, room)
})
.catch(console.error)
Çözüm
Hatalarınızı kontrol etmek, uygulamanız üzerinde kontrol sağlar. Ayrıca zamandan ve paradan tasarruf etmenizi sağlar. Bu, bu yazının sonunu tamamlıyor! Umarım bunu değerli bulmuşsunuzdur ve gelecekte daha fazlasını ararsınız!