- Hey, I'm Immersive Talk
- This article was first published on [Immersive Talk], my personal blogAlso synchronously updated.
- Please indicate the source and copyright information at the beginning of the article when reprinting.
- If this article is helpful to you, pleaseLike、Comment、Forward, support it, thank you!
Talk about asynchronous,Promise
Everyone must be familiar with it. It is our magic tool for handling asynchronous operations.
But even if there isPromise
, Sometimes it is a bit awkward to deal with functions that may be synchronous or asynchronous, or functions that may throw you a synchronization error at any time when starting, which is still a bit awkward.
You know, it's the kind of "I want to use it.".then().catch()
A shuttle, but I'm afraid it's therePromise
The chain collapsed before it started” embarrassment.
Good news is here!
ES2025 I've held up a big move —()
。
()
Who is the sacred place?
To put it bluntly, it isPromise
A static method on it, like a universal starter.
If you throw it a function (regardless of whether it is synchronous or asynchronous, it will return the value or throw it wrong), it can steadily package it into a promise.
The code is roughly like this:
(The function you want to run, ...the parameters that may be required);
Simple and crude, right?
The key is that it is particularly good at dealing with those "uncertainties".
for example:
- If your function issynchronous, return the value directly after execution
X
? That()
I'll give you oneresolved
The status, value isX
Promise. - If it is a functionsynchronousDirect execution
throw new Error()
What about it? (This is the most troublesome thing, and the subsequent code may have collapsed directly in the past)()
Will catch this error and give you onerejected
The state promise, the error is inside, you can use it.catch()
Catch it. It's simply perfect! - If the function itself returns aasynchronousWhere is the promise? no problem,
()
Just use the state of that promise.
Why do we need this thing? Didn’t you live well before?
Well... It is good to live a good life, but it may not be elegant enough, or rather, not worry-free enough.
I remember that when we wanted to handle synchronous/asynchronous functions in the past, we might use it.().then(func)
Is this a trick?
const f = () => ('I should execute it right away!');
().then(f); // But it is stuffed into the micro-task queue
('I executed first...');
// Output:
// I'll execute it first...
// I should execute it immediately!
Mingmingf
It is a synchronous function, and the result isthen
This makes it async execution.
Sometimes we don't want this kind of delay. And, iff
I threw the error before execution.()
But I can't control it.
()
It is to solve this pain point.
It allows your function (if synchronized) to be executed basically immediately, while also ensuring that you can get a promise anyway, and that synchronization errors can be caught chained.
...Uh, or more accurately, it provides a unified, safer way to start Promise.
Come on, let's get the code
- Get the synchronization function:
const syncTask = () => {
('Synchronous task runs~');
return 'Synchronously handled';
};
(syncTask)
.then(res => ('res:', res)) // immediately output "Synchronously done"
.catch(err => ('Error?', err));
// The console will print "Synchronous task to run~" first, and then "Result: Synchronous completion"
- Handling asynchronous functions (this is nothing special, it is just used normally):
const asyncTask = () => new Promise(resolve => setTimeout(() => resolve('Async is OK'), 500));
(asyncTask)
.then(res => ('res:', res)) // After about 500ms, the output is "Asynchronously OK"
.catch(err => ('Error?', err));
- The best place: catch synchronization errors
const potentiallyExplodingTask = () => {
if (() < 0.5) {
// Suppose there is a 50% chance to blow it up directly
throw new Error('Boom! Synchronization error');
}
return 'safe pass';
};
// Try it a few more times and you will see the results
(potentiallyExplodingTask)
.then(res => ('Good luck this time:', res))
.catch(err => ('Catched error:', )); // Can catch that "Boom!"
Even ifpotentiallyExplodingTask
existPromise
The chain was thrown incorrectly before it started "formal".()
Can also catch it steadily and leave it to you.catch()
deal with.
In the past, this may have directly caused the program to crash or need to write additionaltry...catch
It's blocked. (I personally think this is super practical!)
What's good about this thing? Let's summarize:
- Unified entrance:Regardless of whether it is scattered in synchronous asynchronous functions, the promises are all produced, and the subsequent processing logic can be written very consistently. The code looks much more refreshing.
-
Synchronous error insurance:This is the point! Can catch synchronization errors when starting a function, stuff them into the Promise chain, so that you can use it
.catch()
A spoonful of stewed. Avoid nudetry...catch
Or the risk of missing errors. -
Improved readability:The intention is more obvious, just look
()
You know that this is a safe start operation that may be synchronous or asynchronous.
How can I play it in actual combat?
-
Tuning API:
fetch
It returns a promise itself, but the previous URL processing, parameter construction, etc. may be synchronized. What if something goes wrong?- use
(() => fetch(buildUrl(params)))
It's very stable.
// Previous writing function fetchUserData(userId) { try { // Here buildApiUrl may throw errors synchronously const url = buildApiUrl(`/users/${userId}`); return fetch(url).then(res => ()); } catch (err) { return (err); // Manual conversion to Promise error } } // Use the writing method function fetchUserData(userId) { return (() => { const url = buildApiUrl(`/users/${userId}`); return fetch(url).then(res => ()); }); } // Call example fetchUserData('123') .then(data => ('User Data:', data)) .catch(err => ('Failed to obtain user data:', err));
- use
-
Hybrid task chain:For example, first run a synchronous task, and then run an asynchronous task according to the results.
(syncTask).then(res => (() => asyncTask(res)))
It's natural to string together.// Suppose we have a scenario that processes user input function validateInput(input) { // Synchronous verification may throw an error if (!input || < 3) { throw new Error('Input is too short!'); } return ().toLowerCase(); } function saveToDatabase(processedInput) { // Save asynchronously, return to Promise return new Promise((resolve, reject) => { setTimeout(() => { if (processedInput === 'admin') { reject(new Error('Cannot use reserved keyword')); } else { resolve({ success: true, id: () }); } }, 500); }); } // Use to combine these two tasks function processUserInput(rawInput) { return (() => validateInput(rawInput)).then(validInput => (() => saveToDatabase(validInput)) ); } // Test different situations processUserInput('') // Synchronization error .then(result => ('Save successfully:', result)) .catch(err => ('Processing failed:', )); processUserInput('admin') // Asynchronous error .then(result => ('Save successfully:', result)) .catch(err => ('Processing failed:', )); processUserInput('user123') // Success .then(result => ('Save successfully:', result)) .catch(err => ('Processing failed:', ));
-
Database/file operations:The API designs of many libraries may be diverse, some synchronous errors and some asynchronous errors.
Wrap it up and simplifies error handling logic. (Of course, the specific library may have its own best practices, which is just an idea)
// Suppose we have a file operation library, and its API design is a bit messy const fileOps = { readConfig(path) { // This method may throw errors synchronously (such as the path format is incorrect) // It may also return Promise (when actually reading the file) if (!('.json')) { throw new Error('The configuration file must be in JSON format'); } return new Promise((resolve, reject) => { setTimeout(() => { if (('noneexistent')) { reject(new Error('File does not exist')); } else { resolve({ version: '1.0', settings: { theme: 'dark' } }); } }, 100); }); }, }; // If not used, the caller needs to handle the synchronization error itself function loadAppConfig_old(configPath) { try { return (configPath).then(config => { ('Configuration loaded successfully'); return config; }); } catch (err) { ('Synchronous error:', err); return (err); } } // Use it to make the code more concise and error handling more uniform function loadAppConfig(configPath) { return (() => (configPath)).then(config => { ('Configuration loaded successfully'); return config; }); } // Test various situations loadAppConfig('') // Synchronization error - non-JSON files .catch(err => ('Load failed:', )); loadAppConfig('') // Asynchronous error - the file does not exist .catch(err => ('Load failed:', )); loadAppConfig('') // Success .then(config => ('Configuration content:', config)) .catch(err => ('Load failed:', ));
After talking so much, in short...
()
Although this guy seems to be just a small supplement, the pain points it solves are real.
It makes the use of Promise, especially at the starting point of the chain, stronger and more unified.
I personally feel that once everyone gets used to the convenience it brings (especially the synchronization error capture!), they will probably become a regular customer in our toolbox soon.
If you have the chance, you really have to try it!
Other good articles recommended
Get the XLSX preview? Don’t look for it, these libraries (especially the last one) are so delicious!
Practical Sharing] 10 comprehensive analysis of major payment platforms, essential for independent development!
Regarding MCP, you must know these websites!
To do Docx preview, you must make this divine library! !
【Complete Summary】A complete overview of new JavaScript features in the past 5 years
Regarding Node, be sure to learn this 100,000+ Star project!