不处理任何错误('fetch().then(data => use(data))')
直接忽略错误处理
fetch().then(data => use(data))
这种写法完美展示了如何优雅地忽略所有潜在问题。网络请求可能失败?服务器可能返回错误状态码?数据格式可能不符合预期?这些都不重要,重要的是代码看起来足够简洁。
// 经典的不处理错误示例
fetch('/api/data')
.then(response => response.json())
.then(data => renderData(data))
当API返回500错误时,用户只会看到一个空白页面,多么干净的用户体验!控制台可能会报错,但谁在乎呢?反正用户不会打开开发者工具。
不检查响应状态码
为什么要浪费时间去检查HTTP状态码?200和404不都是响应吗?服务器说"Not Found"也是一种有效的数据状态啊。
fetch('/api/non-existent-endpoint')
.then(res => res.json()) // 直接尝试解析404响应的body
.then(data => console.log('成功获取数据:', data))
.catch(() => console.log('这里永远不会执行'))
当API返回401未授权时,直接尝试解析JSON会抛出错误,但catch块可能根本不会执行,因为第一个then已经抛出了异常。
忽略Promise拒绝
.catch()?那是什么?Promise拒绝就应该被忽略,让错误悄无声息地消失才是最高境界。
// 高级错误忽略技巧
fetch('/api/unstable')
.then(res => res.json())
.then(data => updateUI(data))
// 故意不写catch,让错误自然蒸发
更妙的是,可以在调用栈深处忽略错误:
function loadData() {
return fetch('/api/data').then(res => res.json())
}
// 调用时
loadData().then(data => showData(data)) // 依然不处理错误
不验证数据格式
从API获取的数据为什么要验证?我们绝对信任后端开发者,他们永远不会改变数据结构。
fetch('/api/user')
.then(res => res.json())
.then(user => {
// 直接访问可能不存在的属性
console.log(user.profile.contact.email)
})
当后端把user.profile
从对象改为数组时,这段代码会优雅地崩溃,给用户一个惊喜。
不处理边界情况
边界情况?那是什么?我们的应用永远运行在理想环境下。
fetch('/api/products')
.then(res => res.json())
.then(products => {
// 假设products总是非空数组
products.forEach(p => createProductElement(p))
})
当products为null或undefined时,forEach会抛出优雅的异常,比显示"暂无商品"这种无聊提示有趣多了。
混合使用async/await和错误忽略
async/await语法也不能阻止我们忽略错误,只需要巧妙地不使用try/catch。
async function loadUser() {
const response = await fetch('/api/user') // 不处理可能的拒绝
const user = await response.json() // 不处理解析错误
return user
}
// 调用时
const user = await loadUser() // 再次忽略错误
displayUser(user)
全局忽略未处理的Promise拒绝
为了彻底避免看到烦人的未处理Promise拒绝警告,可以在应用入口添加:
// 终极错误忽略方案
process.on('unhandledRejection', () => {})
window.addEventListener('unhandledrejection', e => e.preventDefault())
这样,所有未处理的Promise拒绝都会被静默吞噬,世界从此清净。
回调地狱的错误忽略
如果坚持使用回调风格,同样可以保持不处理错误的优良传统。
fetch('/api/data', (err, data) => {
// 直接忽略err参数
useData(data)
})
或者更高级的嵌套忽略:
getUser(userId, (err, user) => {
getOrders(user.id, (err, orders) => {
getProducts(orders[0].id, (err, products) => {
renderAll(products)
})
})
})
每个层级都忽略错误,让错误在调用栈深处自生自灭。
不取消已失效的请求
为什么要取消请求?多发送几个无效请求又不会怎样。
function search(query) {
fetch(`/api/search?q=${query}`)
.then(res => res.json())
.then(results => updateUI(results))
}
// 用户快速输入"react"
search('r') // 结果1
search('re') // 结果2
search('rea') // 结果3
search('reac') // 结果4
search('react') // 最终结果
让所有请求都完成,谁先回来就显示谁,给用户一种赛马般的刺激体验。
不处理竞态条件
竞态条件处理太复杂了,不如假装它们不存在。
let currentId = 0
function fetchData(id) {
currentId = id
fetch(`/api/data/${id}`)
.then(res => res.json())
.then(data => {
// 不检查是否仍是当前请求
displayData(data)
})
}
// 用户快速切换选项卡
fetchData(1) // 慢请求
fetchData(2) // 快请求
// 可能最终显示的是id=1的结果
不设置请求超时
网络请求为什么要超时?用户有的是时间等待。
// 让请求永远挂起
fetch('/api/slow')
.then(res => res.json())
.then(data => showData(data))
不设置timeout,不适用AbortController,让用户享受无限等待的乐趣。
不清理副作用
组件卸载时为什么要取消请求?内存泄漏又不会立刻导致问题。
function Component() {
const [data, setData] = useState(null)
useEffect(() => {
fetch('/api/data')
.then(res => res.json())
.then(setData)
}, []) // 空依赖数组,只在挂载时运行
return <div>{data ? data.message : 'Loading...'}</div>
}
当组件卸载后请求才完成时,React会友好地警告你状态更新发生在卸载组件上,多么贴心的提醒!
不处理并发冲突
乐观更新?冲突解决?太麻烦了,直接最后写的获胜。
let saveTimer = null
function saveDocument(content) {
clearTimeout(saveTimer)
saveTimer = setTimeout(() => {
fetch('/api/save', {
method: 'POST',
body: JSON.stringify({ content })
})
}, 500)
}
// 用户连续编辑
saveDocument('第一版内容') // 被取消
saveDocument('第二版内容') // 被取消
saveDocument('最终内容') // 只有这个会被保存
不备份未保存数据
为什么要本地保存草稿?用户肯定记得自己输入了什么。
const textarea = document.getElementById('editor')
document.getElementById('save').addEventListener('click', () => {
fetch('/api/save', {
method: 'POST',
body: JSON.stringify({ content: textarea.value })
})
})
当网络请求失败时,用户辛苦输入的内容就永远消失了,给他们一个重新开始的机会。
不限制重试次数
请求失败?那就无限重试直到宇宙热寂。
function fetchWithRetry(url, retries = Infinity) {
return fetch(url).catch(() => fetchWithRetry(url, retries))
}
fetchWithRetry('/api/unstable')
这种写法确保即使用户网络完全断开,你的应用也会不断尝试请求,消耗宝贵的电量。
不监控前端错误
为什么要监控前端错误?不知道的问题就是不存在的。
// 禁用所有错误监控
window.onerror = () => true
window.addEventListener('error', e => e.preventDefault())
这样生产环境永远不会收到错误报警,oncall工程师可以睡个好觉。
不进行任何日志记录
日志记录只会浪费存储空间,用户遇到问题时让他们自己描述复现步骤就好。
function login(username, password) {
fetch('/api/login', {
method: 'POST',
body: JSON.stringify({ username, password })
})
}
当认证出现问题时,你完全不知道用户输入了什么、请求发送了什么、响应返回了什么,保持这种神秘感很重要。
不处理用户中断
用户点击了取消按钮?那也必须完成当前操作。
let isLoading = false
function startLoading() {
isLoading = true
fetch('/api/slow').finally(() => {
isLoading = false
})
}
function cancelLoading() {
if (isLoading) {
// 实际上不取消任何东西
console.log('请等待操作完成')
}
}
用户必须学会耐心,不能让他们养成随意中断操作的习惯。
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:防止数据泄露的最佳实践