// https://devsmitra.medium.com/javascript-error-handling-just-got-a-whole-lot-easier-meet-the-safe-assignment-operator-c372d892d4ed
// without
async function getData() {
try {
const response = await fetch("https://api.example.com/data");
const json = await response.json();
return validationSchema.parse(json);
} catch (error) {
handleError(error);
}
}
// with
async function getData() {
const [fetchError, response]?= await fetch("https://api.example.com/data");
if (fetchError) return handleFetchError(fetchError);
const [jsonError, json]?= await response.json();
if (jsonError) return handleJsonError(jsonError);
const [validationError, data]?= validationSchema.parse(json);
if (validationError) return handleValidationError(validationError);
return data;
}
// https://medium.com/@asierr/javascripts-function-prototype-tostring-just-got-useful-here-s-how-bc617fd7222c
function greet(name) {
return `Hello, ${name}`;
}
console.log(greet.toString());
// result
"function greet(name) {\n return `Hello, ${name}`;\n}"
// any usage
const fn = x => x * 2;
const body = fn.toString();
if (body.includes('x * 2')) {
console.log('Safe to optimize!');
}
/*
Limitations
Doesn’t work on native functions (e.g., Math.max.toString() returns "function max() { [native code] }")
Some minifiers may still mangle formatting
Not recommended for secure comparisons (function source can be identical but semantically different)
*/
// https://javascript.plainenglish.io/the-battle-of-isolation-proxy-vs-web-workers-vs-iframe-in-frontend-development-%EF%B8%8F-3eaeef99a11d
// 1
const sandbox = new Proxy(window, {
get(target, key) {
if (key === 'document') {
throw new Error('No access to DOM!');
}
return Reflect.get(target, key);
},
set(target, key, value) {
if (key === 'location') return false;
return Reflect.set(target, key, value);
}
});
// Running plugin code in sandbox
(function(window) {
try {
window.document.title = 'Hacked!'; // Triggers exception
} catch (err) {
console.error('Illegal operation intercepted:', err);
}
})(sandbox);
// 2
const audit = new Proxy(console, {
get(target, key) {
if (key === 'log') return (...args) => {
recordLog(args); // Log recording
target[key](...args);
};
return target[key];
}
});
sandbox.console = audit;
// https://medium.com/@hxu0407/master-these-8-promise-concurrency-control-techniques-to-significantly-improve-performance-5a1c199b6b3c
// 1. Promise.all: Execute in Parallel and Return Results Together
const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);
const promise3 = Promise.resolve(3);
Promise.all([promise1, promise2, promise3])
.then(results => {
console.log(results); // Output: [1, 2, 3]
});
// 2. Promise.allSettled: Execute in Parallel and Return All States
const promise1 = Promise.resolve(1);
const promise2 = Promise.reject("Error");
const promise3 = Promise.resolve(3);
Promise.allSettled([promise1, promise2, promise3])
.then(results => {
console.log(results);
/* Output:
[
{ status: 'fulfilled', value: 1 },
{ status: 'rejected', reason: 'Error' },
{ status: 'fulfilled', value: 3 }
]
*/
})
// 3. Promise.race: Execute in Parallel and Return the Fastest
const promise1 = new Promise(resolve => setTimeout(() => resolve("Fast"), 100));
const promise2 = new Promise(resolve => setTimeout(() => resolve("Slow"), 500));
Promise.race([promise1, promise2])
.then(result => console.log(result)); // Output: "Fast" (whichever resolves first)
// 4. Promise.any (ES2021): Execute in Parallel and Return the First Fulfilled
const promise1 = Promise.reject("Error 1");
const promise2 = new Promise(resolve => setTimeout(() => resolve("Success"), 200));
const promise3 = Promise.reject("Error 2");
Promise.any([promise1, promise2, promise3])
.then(result => console.log(result)) // Output: "Success"
.catch(error => console.log(error.errors)); // If all reject
// 5. Custom Concurrency Control Function: Limit Max Concurrent Requests
async function limitConcurrency(tasks, limit) {
const results = [];
const running = new Set();
for (const task of tasks) {
const promise = task().then(result => {
running.delete(promise);
return result;
});
running.add(promise);
results.push(promise);
if (running.size >= limit) {
await Promise.race(running);
}
}
return Promise.all(results);
// https://medium.com/@hxu0407/9-smart-ways-to-replace-if-else-in-javascript-28f82ad6dcb9
// 1. Object Mapping Instead of if-else
function getPrice(user) {
if (user.type === 'vip') {
return 'VIP Price';
} else if (user.type === 'svip') {
return 'SVIP Price';
} else if (user.type === 'vvip') {
return 'VVIP Price';
} else {
return 'Regular Price';
}
}
// better
const priceStrategy = {
vip: () => 'VIP Price',
svip: () => 'SVIP Price',
vvip: () => 'VVIP Price',
default: () => 'Regular Price'
};
function getPrice(user) {
return (priceStrategy[user.type] || priceStrategy.default)();
}
// 2. Replace Multiple Conditions with Array.includes
if (status === 'failed' || status === 'error' || status === 'rejected') {
handleError();
}
// better
const errorStatus = ['failed', 'error', 'rejected'];
if (errorStatus.includes(status)) {
handleError();
}
// 3. Chained Ternary Operators
let message;
if (score >= 90) {
message = 'Excellent';
} else if (score >= 80) {
message = 'Good';
} else if (score >= 60) {
message = 'Pass';
} else {
message = 'Fail';
}
// better
const message =
score >= 90 ? 'Excellent' :
score >= 80 ? 'Good' :
score >= 60 ? 'Pass' :
'Fail';
// 4. Logical Operators && and ||
// Replacing a simple `if`
user.isAdmin && showAdminPanel();
// Setting default values
const name = user.name || 'unnamed';
// Nullish coalescing
const count = data?.users ?? [];
// 5. Switch-Case with Pattern Matching
const actions = new Map([
[/^vip/, handleVip],
[/^admin/, handleAdmin],
[/^user/, handleUser]
]);
/*or
const actions = [
[/^vip/, handleVip],
[/^admin/, handleAdmin],
[/^user/, handleUser]
];
*/
const handleRequest = (type) => {
const action = [...actions].find(([key]) => key.test(type));
return action ? action[1]() : handleDefault();
};
// 6. Using Proxy for Conditional Interception
const handler = {
get: (target, property) => {
return property in target ? target[property] : target.default;
}
};
const services = new Proxy({
admin: () => 'Admin Service',
user: () => 'User Service',
default: () => 'Default Service'
}, handler);
// 7. Functional Approach
// Composing conditions
const isAdult = age => age >= 18;
const hasPermission = role => ['admin', 'superuser'].includes(role);
const canAccess = user => isAdult(user.age) && hasPermission(user.role);
// Usage
users.filter(canAccess).forEach(grantAccess);
// 8. State Machine Pattern
const stateMachine = {
draft: {
publish: 'published',
delete: 'deleted'
},
published: {
unpublish: 'draft',
archive: 'archived'
},
archived: {
restore: 'draft'
}
};
const changeState = (currentState, action) =>
stateMachine[currentState]?.[action] || currentState;
// 9. Use Decorators to Handle Conditional Logic
function checkPermission(target, name, descriptor) {
const original = descriptor.value;
descriptor.value = function (...args) {
if (this.user?.hasPermission) {
return original.apply(this, args);
}
throw new Error('No permission');
};
return descriptor;
}
class Document {
@checkPermission
edit() {
// Edit the document
}
}
/*
Why It’s a Problem:
Direct DOM manipulation triggers reflows and repaints, slowing down rendering.
Inserting elements one by one instead of batching updates increases the number of re-renders.
Modifying styles directly forces layout recalculations.
*/
// BAD: Multiple reflows
for (let i = 0; i < 1000; i++) {
const div = document.createElement('div');
div.textContent = `Item ${i}`;
document.body.appendChild(div);
}
// GOOD: Batch updates using DocumentFragment
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
const div = document.createElement('div');
div.textContent = `Item ${i}`;
fragment.appendChild(div);
}
document.body.appendChild(fragment);
Místo načtení celé aplikace najednou můžeš načítat moduly až když jsou potřeba:
// Běžný statický import
import { heavyFunction } from './heavyModule.js';
// Dynamický import - načte se jen když je potřeba
button.addEventListener('click', async () => {
const { heavyFunction } = await import('./heavyModule.js');
heavyFunction();
});
Můžeš načítat moduly jen za určitých podmínek:
async function loadFeature(featureName) {
if (featureName === 'chart') {
const { createChart } = await import('./chartModule.js');
createChart();
} else if (featureName === 'table') {
const { createTable } = await import('./tableModule.js');
createTable();
}
}
// Místo tohoto statického importu
import HeavyComponent from '@/components/HeavyComponent.vue';
// Můžeš použít dynamický import
const HeavyComponent = defineAsyncComponent(() =>
import('@/components/HeavyComponent.vue')
);
Zmenšíš hlavní bundle a zrychlíš tak první vykreslení:
// V Nuxt 3 můžeš dynamicky importovat i stránky
const routes = [
{
path: '/',
component: () => import('./Home.vue')
},
{
path: '/dashboard',
component: () => import('./Dashboard.vue') // Načte se až při navigaci
}
]
async function loadConfigBasedOnEnvironment() {
if (process.env.NODE_ENV === 'development') {
return import('./config.dev.json');
} else {
return import('./config.prod.json');
}
}
Když změníš jeden modul, prohlížeč může znovu stáhnout jen tento modul, ne celý bundle.
Dynamické importy mohou někdy pomoct vyřešit cyklické závislosti:
// moduleA.js
export function funcA() {
console.log('Function A');
}
export async function funcThatUsesB() {
const moduleB = await import('./moduleB.js');
moduleB.funcB();
}
// moduleB.js
import { funcA } from './moduleA.js';
export function funcB() {
console.log('Function B calls:');
funcA();
}
// 1
await new Promise(resolve => setTimeout(resolve, 1000)); // wait for 1 sec
// 2
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
<!-- 1. PROPS -->
<!-- JS -->
<script setup>
import { defineProps } from 'vue';
const props = defineProps({
foo: { type: String, required: true },
bar: Number,
});
// props.foo is a string
// props.bar is a number or undefined
</script>
<!-- TS -->
<script setup lang="ts">
const props = defineProps<{
foo: string;
bar?: number;
}>()
</script>
<script setup lang="ts">
interface Props {
foo: string;
bar?: number;
}
const props = defineProps<Props>()
</script>
<!-- 2. EMITS -->
<!-- JS -->
<script setup>
const emit = defineEmits(['change', 'update'])
</script>
<!-- TS -->
<script setup lang="ts">
const emit = defineEmits<{
change: [id: number]
update: [value: string]
}>()
</script>
<!-- 3. Typing Ref and Reactive Data => Inference -->
<script setup>
import { ref } from 'vue';
const count = ref(0);
count.value = 'string'; // error, inference, we expect number
</script>
<!-- 4. Typing Server Responses -->
<script setup lang="ts">
import { ref, onMounted } from 'vue';
interface User {
id: number;
name: string;
email: string;
}
const userData = ref<User | null>(null);
onMounted(async () => {
const response = await fetch('https://api.example.com/user');
const data: User = await response.json();
userData.value = data; // TypeScript ensures data usages match the User interface
});
</script>
<!-- 5. Typing Computed Data -->
import { ref, computed } from 'vue'
const count = ref(0)
// inferred type: ComputedRef<number>
const double = computed(() => count.value * 2)
// => TS Error: Property 'split' does not exist on type 'number'
const result = double.value.split('')
// or explicitely define return type
const double = computed<number>(() => {
// type error if this doesn't return a number
})
<!-- 6. Typing Scoped Slots-->
<template>
<slot :msg="message"></slot>
</template>
<script setup lang="ts">
const message = 'Hello, Vue!';
const slots = defineSlots<{
default: (props: { msg: string }) => any;
}>()
</script>
<!-- 7. Typing Template Refs -->
<script setup lang="ts">
import { useTemplateRef, onMounted } from 'vue';
const myInput = useTemplateRef('my-input');
onMounted(() => {
myInput.value?.focus();
});
</script>
<template>
<input ref="my-input" />
</template>
<!-- 8. Typing Provide/Inject -->
<!-- ParentComponent.vue -->
<script setup lang="ts">
import { provide } from 'vue';
const theme = 'dark';
provide('theme', theme);
</script>
<!-- ChildComponent.vue -->
<script setup lang="ts">
import { inject } from 'vue';
const theme = inject<string>('theme'); // Inject with expected type
// TypeScript ensures that 'theme' is of type string
</script>
<!-- 9. Generics -->
<script setup lang="ts" generic="T">
defineProps<{
items: T[]; // Array of items of type T
selected: T; // Single selected item of type T
}>()
</script>
<!-- 10. Typed Composables -->
// useUser.ts
import { ref } from 'vue';
interface User {
id: number;
name: string;
age: number;
}
export function useUser() {
const user = ref<User | null>(null);
function fetchUser(id: number) {
// Fetching user logic
user.value = { id, name: 'John Doe', age: 30 };
}
return { user, fetchUser };
}
/*
@url https://levelup.gitconnected.com/7-simple-async-await-tricks-for-developers-who-hate-asynchronous-javascript-fe370ac7fe72
*/
// 1. Use Promise.allSettled() for Safer Batch Processing
const results = await Promise.allSettled([
fetchData1(),
fetchData2(),
fetchData3(),
]);
results.forEach(result => {
if (result.status === 'fulfilled') {
console.log('Success:', result.value);
} else {
console.error('Failed:', result.reason);
}
});
// 2. Use Timeouts to Prevent Hanging Promises
const withTimeout = (promise, ms) =>
Promise.race([
promise,
new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), ms)),
]);
try {
const data = await withTimeout(fetchData(), 5000);
} catch (err) {
console.error(err.message); // "Timeout" if it takes too long
}
// 3. Sequential Loops with Async/Await
const urls = ['url1', 'url2', 'url3'];
for (const url of urls) {
const data = await fetch(url);
console.log(data);
}
// 4. Dynamic Delays with await
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
console.log('Start');
await delay(2000); // Waits 2 seconds
console.log('End');
// 5. Always Use try...catch Inside Async Functions
async function fetchData(url) {
try {
const response = await fetch(url);
if (!response.ok) throw new Error('Fetch failed');
return await response.json();
} catch (err) {
console.error('Error:', err.message);
return null;
}
}
// 6. await Outside Loops to Batch Workloads
const urls = ['url1', 'url2', 'url3'];
const responses = await Promise.all(urls.map(url => fetch(url)));
const data = await Promise.all(responses.map(res => res.json()));
console.log(data);
// 7 ... fking yield => dont care