Skip to content

merge 1.6.2025 #55

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 26 commits into from
Jun 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
3de63df
promise.all task
iliakan Mar 24, 2025
ef31066
minor fixes
iliakan Mar 24, 2025
de4247b
minor fixes
iliakan Mar 24, 2025
0af25bc
minor fixes
iliakan Mar 24, 2025
d932e52
minor fixes
iliakan Mar 24, 2025
f0d8abb
minor fixes
iliakan Mar 24, 2025
f775835
minor fixes
iliakan Mar 24, 2025
0760c90
minor fixes
iliakan Mar 24, 2025
5dea441
minor fixes
iliakan Mar 24, 2025
035c526
minor fixes
iliakan Mar 24, 2025
4c4598b
Fix for #3826 - Removed errorception.com from the respective md file.
Paramesh-T-S Mar 29, 2025
02b96ce
Merge branch 'master' of github.com:javascript-tutorial/en.javascript…
iliakan Mar 31, 2025
cde189d
Update Safari settings screenshots
dangerman Apr 2, 2025
78c6c44
Update Safari devtools instructions
dangerman Apr 2, 2025
e88c212
Update Function object, NFE article
rahulrao0209 Apr 6, 2025
a711a1f
Merge pull request #3830 from Paramesh-T-S/Issue_fix_Outdate_-link_in…
iliakan Apr 8, 2025
efaa9aa
sentry.io added as per suggestion - https://github.com/javascript-tut…
Paramesh-T-S Apr 8, 2025
6cc5077
Merge pull request #3835 from Paramesh-T-S/Issue_fix_Outdate_-link_in…
iliakan Apr 9, 2025
81cfee9
Update article.md
rahulrao0209 Apr 13, 2025
e2d8ebe
Merge pull request #3836 from rahulrao0209/patch-3
smith558 Apr 13, 2025
6bbdd0c
Merge pull request #3834 from rahulrao0209/patch-2
smith558 Apr 13, 2025
d3c395c
Merge pull request #3832 from dangerman/update-safari-devtools-screen…
smith558 Apr 13, 2025
540d753
Replace with up to date screenshots
smith558 Apr 13, 2025
19a0f78
merging all conflicts
iliakan May 26, 2025
7a1dc79
Merge pull request #222 from javascript-tutorial/sync-540d753e
otmon76 Jun 1, 2025
ca57c28
Update article.md
otmon76 Jun 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions 1-js/01-getting-started/4-devtools/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Otevřou se vývojářské nástroje na záložce „Console“.

Budou vypadat zhruba takto:

![chrome](chrome.png)
![chrome](chrome.webp)

Vzhled vývojářských nástrojů závisí na vaší verzi Chrome. Čas od času se mění, ale měl by se podobat obrázku.

Expand All @@ -49,8 +49,8 @@ Jejich vzhled je vcelku podobný. Až budete vědět, jak používat nástroje v

Safari (prohlížeč pro Mac, není podporován ve Windows nebo Linuxu) je v tomto ohledu trochu zvláštní. Nejprve musíme povolit „menu Vývoj“.

Otevřete „Preferences“ a jděte na záložku „Advanced“. Dole uvidíte checkbox, který zaškrtněte:

Otevřete „Settings“ a jděte na záložku „Advanced“. Dole uvidíte checkbox, který zaškrtněte:
![safari](safari.png)

Nyní můžete zapínat konzoli pomocí `key:Cmd+Opt+C`. Všimněte si také, že v horním menu se objevila nová položka s názvem „Develop“ („Vývoj“), která obsahuje mnoho příkazů a nastavení.
Expand Down
Binary file removed 1-js/01-getting-started/4-devtools/chrome.png
Binary file not shown.
Binary file added 1-js/01-getting-started/4-devtools/chrome.webp
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified 1-js/01-getting-started/4-devtools/safari.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified 1-js/01-getting-started/4-devtools/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion 1-js/06-advanced-functions/06-function-object/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ welcome(); // Hello, Guest (nested call works)

Now it works, because the name `"func"` is function-local. It is not taken from outside (and not visible there). The specification guarantees that it will always reference the current function.

The outer code still has its variable `sayHi` or `welcome`. And `func` is an "internal function name", the way for the function to can call itself reliably.
The outer code still has its variable `sayHi` or `welcome`. And `func` is an "internal function name", the way for the function to call itself reliably.

```smart header="There's no such thing for Function Declaration"
The "internal name" feature described here is only available for Function Expressions, not for Function Declarations. For Function Declarations, there is no syntax for adding an "internal" name.
Expand Down
2 changes: 1 addition & 1 deletion 1-js/06-advanced-functions/10-bind/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ funcUser(); // John
*/!*
```

Here `func.bind(user)` as a "bound variant" of `func`, with fixed `this=user`.
Here `func.bind(user)` is a "bound variant" of `func`, with fixed `this=user`.

All arguments are passed to the original `func` "as is", for instance:

Expand Down
2 changes: 1 addition & 1 deletion 1-js/10-error-handling/1-try-catch/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,7 @@ For instance:

The role of the global handler `window.onerror` is usually not to recover the script execution -- that's probably impossible in case of programming errors, but to send the error message to developers.

There are also web-services that provide error-logging for such cases, like <https://errorception.com> or <https://www.muscula.com>.
There are also web-services that provide error-logging for such cases, like <https://muscula.com> or <https://www.sentry.io>.

They work like this:

Expand Down
113 changes: 113 additions & 0 deletions 1-js/11-async/08-async-await/04-promise-all-failure/solution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@

The root of the problem is that `Promise.all` immediately rejects when one of its promises rejects, but it do nothing to cancel the other promises.

In our case, the second query fails, so `Promise.all` rejects, and the `try...catch` block catches this error.Meanwhile, other promises are *not affected* - they independently continue their execution. In our case, the third query throws an error of its own after a bit of time. And that error is never caught, we can see it in the console.

The problem is especially dangerous in server-side environments, such as Node.js, when an uncaught error may cause the process to crash.

How to fix it?

An ideal solution would be to cancel all unfinished queries when one of them fails. This way we avoid any potential errors.

However, the bad news is that service calls (such as `database.query`) are often implemented by a 3rd-party library which doesn't support cancellation. Then there's no way to cancel a call.

As an alternative, we can write our own wrapper function around `Promise.all` which adds a custom `then/catch` handler to each promise to track them: results are gathered and, if an error occurs, all subsequent promises are ignored.

```js
function customPromiseAll(promises) {
return new Promise((resolve, reject) => {
const results = [];
let resultsCount = 0;
let hasError = false; // we'll set it to true upon first error

promises.forEach((promise, index) => {
promise
.then(result => {
if (hasError) return; // ignore the promise if already errored
results[index] = result;
resultsCount++;
if (resultsCount === promises.length) {
resolve(results); // when all results are ready - successs
}
})
.catch(error => {
if (hasError) return; // ignore the promise if already errored
hasError = true; // wops, error!
reject(error); // fail with rejection
});
});
});
}
```

This approach has an issue of its own - it's often undesirable to `disconnect()` when queries are still in the process.

It may be important that all queries complete, especially if some of them make important updates.

So we should wait until all promises are settled before going further with the execution and eventually disconnecting.

Here's another implementation. It behaves similar to `Promise.all` - also resolves with the first error, but waits until all promises are settled.

```js
function customPromiseAllWait(promises) {
return new Promise((resolve, reject) => {
const results = new Array(promises.length);
let settledCount = 0;
let firstError = null;

promises.forEach((promise, index) => {
Promise.resolve(promise)
.then(result => {
results[index] = result;
})
.catch(error => {
if (firstError === null) {
firstError = error;
}
})
.finally(() => {
settledCount++;
if (settledCount === promises.length) {
if (firstError !== null) {
reject(firstError);
} else {
resolve(results);
}
}
});
});
});
}
```

Now `await customPromiseAllWait(...)` will stall the execution until all queries are processed.

This is a more reliable approach, as it guarantees a predictable execution flow.

Lastly, if we'd like to process all errors, we can use either use `Promise.allSettled` or write a wrapper around it to gathers all errors in a single [AggregateError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError) object and rejects with it.

```js
// wait for all promises to settle
// return results if no errors
// throw AggregateError with all errors if any
function allOrAggregateError(promises) {
return Promise.allSettled(promises).then(results => {
const errors = [];
const values = [];

results.forEach((res, i) => {
if (res.status === 'fulfilled') {
values[i] = res.value;
} else {
errors.push(res.reason);
}
});

if (errors.length > 0) {
throw new AggregateError(errors, 'One or more promises failed');
}

return values;
});
}
```
79 changes: 79 additions & 0 deletions 1-js/11-async/08-async-await/04-promise-all-failure/task.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@

# Dangerous Promise.all

`Promise.all` is a great way to parallelize multiple operations. It's especially useful when we need to make parallel requests to multiple services.

However, there's a hidden danger. We'll see an example in this task and explore how to avoid it.

Let's say we have a connection to a remote service, such as a database.

There're two functions: `connect()` and `disconnect()`.

When connected, we can send requests using `database.query(...)` - an async function which usually returns the result but also may throw an error.

Here's a simple implementation:

```js
let database;

function connect() {
database = {
async query(isOk) {
if (!isOk) throw new Error('Query failed');
}
};
}

function disconnect() {
database = null;
}

// intended usage:
// connect()
// ...
// database.query(true) to emulate a successful call
// database.query(false) to emulate a failed call
// ...
// disconnect()
```

Now here's the problem.

We wrote the code to connect and send 3 queries in parallel (all of them take different time, e.g. 100, 200 and 300ms), then disconnect:

```js
// Helper function to call async function `fn` after `ms` milliseconds
function delay(fn, ms) {
return new Promise((resolve, reject) => {
setTimeout(() => fn().then(resolve, reject), ms);
});
}

async function run() {
connect();

try {
await Promise.all([
// these 3 parallel jobs take different time: 100, 200 and 300 ms
// we use the `delay` helper to achieve this effect
*!*
delay(() => database.query(true), 100),
delay(() => database.query(false), 200),
delay(() => database.query(false), 300)
*/!*
]);
} catch(error) {
console.log('Error handled (or was it?)');
}

disconnect();
}

run();
```

Two of these queries happen to be unsuccessful, but we're smart enough to wrap the `Promise.all` call into a `try..catch` block.

However, this doesn't help! This script actually leads to an uncaught error in console!

Why? How to avoid it?