/ Gists / JavaScript

Gists - JavaScript

On gists

Delay in JS

JavaScript

sleep.js #

// 1
await new Promise(resolve => setTimeout(resolve, 1000)); // wait for 1 sec


// 2
function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}
   
   
   

On gists

Better Vue components with TS

JavaScript Typescript Vue.js

better-vue-with-components.vue #

<!-- 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 };
}

On gists

Async/Await Tricks

JavaScript

index.js #

/*
@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

On gists

HTML 5: Restricted datalist

JavaScript HTML

index.html #

<!DOCTYPE html>
<html lang="cs">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Výběr s Datalist</title>
  <script>
    function validateInput(input) {
      const datalist = document.getElementById('fruit-list');
      const options = datalist.getElementsByTagName('option');
      const values = Array.from(options).map(option => option.value);

      if (!values.includes(input.value)) {
        input.value = ''; // Vymaže hodnotu, pokud není v datalistu
      }
    }
  </script>
</head>
<body>
  <form>
    <label for="fruit">Vyberte ovoce:</label>
    <input type="text" id="fruit" name="fruit" list="fruit-list" oninput="validateInput(this)">
    <datalist id="fruit-list">
      <option value="Jablko">
      <option value="Banán">
      <option value="Třešně">
      <option value="Datle">
    </datalist>
    <button type="submit">Odeslat</button>
  </form>
</body>
</html>

On gists

Pipeline operator

JavaScript

index.js #

/* https://medium.com/@asierr/javascripts-pipeline-operator-the-game-changer-for-cleaner-code-e9eb46179510 */

const first = (x) => x + 1 
const second = (x) => x + 2 
const last = (x) => x + 1000 


const x = 0

const result = first(second(last(x)))
const result2 = x |> increment |> square |> double;


console.log(result)
console.log(result2)



/* examples */

// before
fetch('/api/data')
  .then(response => response.json())
  .then(data => transformData(data))
  .then(filteredData => display(filteredData));

// after
fetch('/api/data')
  .then(response => response.json())
  |> transformData
  |> display;


// after with await
const data = await fetchData() |> parseData |> processData


// before
const slug = replaceSpaces(toLowerCase(trim(userInput)));

// after
const slug = userInput |> trim |> toLowerCase |> replaceSpaces;

On gists

Composed Path

JavaScript

index.js #

document.querySelector('button').addEventListener('click', (e) => {
  console.log(e.composedPath())
})

On gists

Regexp - "v" modifier multilang chars

JavaScript

regex.js #

const nameRegex = /^\p{Letter}+$/v;

function validateName(name) {
  if (nameRegex.test(name)) {
    console.log(`${name} is a valid name.`);
  } else {
    console.log(`${name} contains invalid characters.`);
  }
}

validateName("John"); // "John is a valid name."
validateName("María"); // "María is a valid name."
validateName("佐藤"); // "佐藤 is a valid name."
validateName("John123"); // "John123 contains invalid characters."

On gists

Usefull detach handler

JavaScript

detach.js #

/*
https://javascript.plainenglish.io/7-infamous-javascript-bugs-that-shook-the-internet-3cf8f8f76098
*/

// Proper event listener cleanup to prevent memory leaks
function attachEvent() {
  const btn = document.querySelector("#myButton");
  const handleClick = () => console.log("Button clicked!");
  btn.addEventListener("click", handleClick);

  // Return a function to remove the listener and free up memory
  return () => btn.removeEventListener("click", handleClick);
}
const detach = attachEvent();
detach(); // Cleanup resources

On gists

Img.decode() // nahrada za onload()

JavaScript

img-decode.js #

const img = document.querySelector('img')
const tempImg = new Image()

tempImg.src = 'https://masoprofit.cz/storage/images/1600x2000/41847.png.webp'

tempImg.decode().then(() => {
  img.src = tempImg.src
}).catch(e => {
  console.log(e)
})

On gists

Promise.all

JavaScript

examples.js #

// Parallel
async function getData() {
    const [user, posts] = await Promise.all([
        fetchUserData(),
        fetchPostsData()
    ]);
    console.log(user, posts);
}


// non parallel
function getData() {
    return Promise.all([fetchUser(), fetchPosts()])
        .then(([user, posts]) => {
            console.log(user, posts);
        })
        .catch((error) => {
            console.error(error); 
        });
}