title: '解构赋值中设置初始值不成功,原值为null的问题',
        title: '明明程序报错,但是控制台不打印错误的几种情况(别怀疑,一定是代码问题,而不是程序运行太久)',
flex-api
LCJ-MinYa 2 months ago
parent ffdc2bc8b1
commit 91d1cbce10

@ -154,6 +154,14 @@ const titleArr = [
key: 'computedWithEnumList',
title: '接口返回数据需要根据多个枚举值动态计算结果渲染(多个枚举值是接口返回,并且不知道具体返回时间)',
},
{
key: 'dsAssign',
title: '解构赋值中设置初始值不成功原值为null的问题',
},
{
key: 'catchError',
title: '明明程序报错,但是控制台不打印错误的几种情况(别怀疑,一定是代码问题,而不是程序运行太久)',
},
];
// @/views/demo/**/*.vue

@ -0,0 +1,263 @@
# 明明程序报错,但是控制台不打印错误的几种情况(别怀疑,一定是代码问题,而不是程序运行太久)
这是一个很常见但容易让人困惑的问题。以下是程序报错但控制台不打印错误的几种常见情况:
## 1. **异步错误未被捕获**
### Promise 错误
```javascript
// ❌ 错误不会打印到控制台
new Promise((resolve, reject) => {
throw new Error('Promise error');
});
// ✅ 需要 catch 处理
new Promise((resolve, reject) => {
throw new Error('Promise error');
}).catch(error => {
console.error('Caught:', error);
});
```
### async/await 未捕获
```javascript
// ❌ 错误不会打印
async function test() {
throw new Error('Async error');
}
test();
// ✅ 需要 try-catch 或外层 catch
async function test() {
throw new Error('Async error');
}
test().catch(error => console.error('Caught:', error));
```
## 2. **setTimeout/setInterval 中的错误**
```javascript
// ❌ 错误不会传播到外层
setTimeout(() => {
throw new Error('Timeout error');
}, 0);
// ✅ 需要在内部 try-catch
setTimeout(() => {
try {
throw new Error('Timeout error');
} catch (error) {
console.error('Caught in timeout:', error);
}
}, 0);
```
## 3. **事件监听器中的错误**
```javascript
// ❌ 错误被事件系统吞掉
element.addEventListener('click', () => {
throw new Error('Event handler error');
});
// ✅ 需要内部 try-catch
element.addEventListener('click', () => {
try {
throw new Error('Event handler error');
} catch (error) {
console.error('Caught in event:', error);
}
});
```
## 4. **微任务队列中的错误**
```javascript
// ❌ queueMicrotask 中的错误
queueMicrotask(() => {
throw new Error('Microtask error');
});
// ✅ 需要包装处理
queueMicrotask(() => {
try {
throw new Error('Microtask error');
} catch (error) {
console.error('Caught in microtask:', error);
}
});
```
## 5. **Web Workers 中的错误**
```javascript
// worker.js
// ❌ 错误不会自动传递到主线程
throw new Error('Worker error');
// ✅ 需要通过 onerror 或 postMessage
self.onerror = function(error) {
console.error('Worker error:', error);
return false; // 返回 false 让错误冒泡到主线程
};
```
## 6. **模块加载错误**
```javascript
// ❌ ES6 模块中的顶级错误可能被静默处理
import './module-that-throws.js'; // 模块内部直接 throw
// ✅ 使用动态导入捕获
import('./module-that-throws.js')
.catch(error => console.error('Module load error:', error));
```
## 7. **被 try-catch 吞掉的错误**
```javascript
// ❌ 错误被捕获但没有处理
try {
throw new Error('Some error');
} catch (error) {
// 没有 console.error错误就消失了
}
// ❌ 更隐蔽的catch 块自身出错
try {
throw new Error('First error');
} catch (error) {
console.nonExistentMethod(); // 这个错误不会被捕获!
}
```
## 8. **跨域脚本错误**
```javascript
// ❌ 跨域脚本的错误信息受限
<script src="https://other-domain.com/script.js"></script>
// 浏览器出于安全考虑,只会显示 "Script error."
```
## 9. **Console 被重写**
```javascript
// ❌ 有人重写了 console.error
const originalError = console.error;
console.error = () => {}; // 静默所有错误
// 检查 console 是否被篡改
if (console.error.toString().includes('[native code]')) {
console.log('Console is native');
} else {
console.log('Console has been overwritten!');
}
```
## 10. **错误在框架中被处理**
### React 的错误边界
```jsx
// ❌ React 16+ 的错误被错误边界捕获
class ErrorBoundary extends React.Component {
componentDidCatch(error, info) {
// 如果没有 console.error错误不会显示
// console.error('Error caught by boundary:', error);
}
render() {
return this.props.children;
}
}
```
### Vue 的错误处理
```javascript
// ❌ Vue 全局错误处理器
Vue.config.errorHandler = function (err, vm, info) {
// 如果没有处理,错误不会显示
// console.error('Vue error:', err);
};
```
## 11. **Node.js 特定情况**
### 未监听的 'error' 事件
```javascript
// ❌ EventEmitter 的 error 事件需要监听
const stream = createReadStream('nonexistent.txt');
// 如果没有 error 监听器,错误会抛出并崩溃进程
// ✅ 必须监听 error 事件
stream.on('error', (error) => {
console.error('Stream error:', error);
});
```
### Domain 模块(已废弃但可能遇到)
```javascript
const domain = require('domain');
const d = domain.create();
// ❌ Domain 可能吞掉错误
d.on('error', (err) => {
// 如果没有处理,错误消失
});
d.run(() => {
throw new Error('Domain error');
});
```
## 调试和诊断技巧
### 1. **全局错误监听器**
```javascript
// 捕获未处理的 Promise 错误
window.addEventListener('unhandledrejection', event => {
console.error('Unhandled promise rejection:', event.reason);
event.preventDefault(); // 阻止默认错误输出
});
// 捕获全局错误
window.addEventListener('error', event => {
console.error('Global error:', event.error);
});
// Node.js
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
});
process.on('uncaughtException', (error) => {
console.error('Uncaught Exception:', error);
});
```
### 2. **启用所有错误显示**
```javascript
// Chrome DevTools
// 1. 打开 DevTools → Sources
// 2. 点击 Pause on exceptions 按钮(⏸️)
// 3. 勾选 "Pause on caught exceptions"
// Node.js 调试
node --inspect app.js
// 或使用 ndb、node --inspect-brk
```
### 3. **检查控制台过滤器**
有时控制台过滤器可能被设置为隐藏错误:
- 检查 Console 顶部的过滤选项
- 确保 "Errors", "Warnings" 没有被过滤掉
- 尝试点击 "Default levels" → "All levels"
### 4. **最小化复现**
```javascript
// 创建一个最小测试
console.log('Script is running');
setTimeout(() => {
console.log('About to throw...');
throw new Error('Test error');
}, 1000);
```
## 总结
当错误不显示时,通常是因为:
1. **异步上下文**中的错误
2. **被某种机制捕获**但未处理
3. **框架或环境**的特定错误处理
4. **控制台配置**问题
最好的做法是始终添加全局错误监听器,并在开发时启用"捕获异常时暂停"功能。

@ -0,0 +1,18 @@
<template>
<div
class="markdown-body"
v-html="htmlStr"
/>
</template>
<script setup>
import { ref } from 'vue';
import { marked } from 'marked';
import { getMarkdownContent } from '@/utils/tools';
const htmlStr = ref('');
getMarkdownContent('./md/catchError.md').then((res) => {
htmlStr.value = marked(res);
});
</script>

@ -0,0 +1,126 @@
# js 解构赋值中设置初始值不成功原值为null的问题
在 JavaScript 解构赋值中,当原值为 `null` 时,设置默认值(初始值)可能会失败。这是因为 `null` 被认为是一个有效的值(虽然为空),解构赋值不会将其视为 `undefined`
## 问题示例
```javascript
// 正常情况undefined 会触发默认值
const obj1 = { a: undefined, b: 2 };
const { a = 1, b = 1 } = obj1;
console.log(a); // 1 ✅ 默认值生效
console.log(b); // 2
// 问题情况null 不会触发默认值
const obj2 = { a: null, b: 2 };
const { a = 1, b = 1 } = obj2;
console.log(a); // null ❌ 默认值不生效
console.log(b); // 2
```
## 解决方案
### 1. **使用逻辑或运算符(||**
```javascript
const obj = { a: null, b: 2 };
const { a, b } = obj;
const aWithDefault = a || 1; // 如果 a 是 null、undefined、0、""、false 等,使用默认值
console.log(aWithDefault); // 1
```
### 2. **使用空值合并运算符(??ES2020**
```javascript
const obj = { a: null, b: 2 };
const { a, b } = obj;
const aWithDefault = a ?? 1; // 只在 a 是 null 或 undefined 时使用默认值
console.log(aWithDefault); // 1
```
### 3. **解构后处理**
```javascript
const obj = { a: null, b: 2 };
let { a, b } = obj; // !!!!!请注意下面如果要重新设置a的值必须使用let解构如果const会报错
a = a === null ? 1 : a;
console.log(a); // 1
```
### 4. **使用函数包装**
```javascript
function destructureWithDefaults(obj, defaults) {
const result = { ...defaults };
for (const key in obj) {
if (obj[key] !== undefined) {
result[key] = obj[key];
}
}
return result;
}
const obj = { a: null, b: 2 };
const { a, b } = destructureWithDefaults(obj, { a: 1, b: 1 });
console.log(a); // null
console.log(b); // 2
```
### 5. **处理嵌套解构**
```javascript
const obj = {
user: null,
settings: { theme: 'dark' }
};
// 嵌套解构也需要处理 null
const {
user = {}, // 默认值不会生效,因为 user 是 null
settings = {}
} = obj || {}; // 先确保 obj 不是 null
// 更好的方式
const safeObj = obj || {};
const safeUser = safeObj.user || {};
const safeSettings = safeObj.settings || {};
```
### 6. **自定义解构辅助函数**
```javascript
function safeDestructure(obj, defaults) {
return Object.keys(defaults).reduce((acc, key) => {
const value = obj[key];
acc[key] = value === null || value === undefined ? defaults[key] : value;
return acc;
}, {});
}
const obj = { a: null, b: 2, c: undefined };
const { a, b, c } = safeDestructure(obj, { a: 1, b: 1, c: 3, d: 4 });
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
```
### 7. **使用 TypeScript编译时检查**
```typescript
interface MyObject {
a: number | null;
b: number;
}
const obj: MyObject = { a: null, b: 2 };
const { a = 1, b = 1 } = obj; // TypeScript 会警告可能的问题
// 需要显式处理
const safeA = a ?? 1;
```
## 最佳实践建议
1. **了解数据来源**:如果数据可能包含 `null`,提前处理
2. **使用空值合并运算符(??**ES2020+ 环境的最佳选择
3. **数据清洗**:在解构前将 `null` 转换为 `undefined`
```javascript
const cleanObj = Object.fromEntries(
Object.entries(obj).map(([k, v]) => [k, v === null ? undefined : v])
);
const { a = 1 } = cleanObj;
```
4. **防御性编程**:对可能为 `null` 的层级都进行保护
记住:解构赋值的默认值只在属性值为 `undefined` 时生效,`null` 是一个明确的值,不会触发默认值。

@ -0,0 +1,18 @@
<template>
<div
class="markdown-body"
v-html="htmlStr"
/>
</template>
<script setup>
import { ref } from 'vue';
import { marked } from 'marked';
import { getMarkdownContent } from '@/utils/tools';
const htmlStr = ref('');
getMarkdownContent('./md/dsAssign.md').then((res) => {
htmlStr.value = marked(res);
});
</script>
Loading…
Cancel
Save