Bye Bye, Try-Catch Blocks: Meet JavaScript's Safe Assignment Operator Proposal😉
Dharmendra Kumar

Dharmendra Kumar @dharamgfx

About: ⚡I’m a curious coder who loves building things! Whether it’s creating beautiful website designs or making sure the behind-the-scenes stuff runs smoothly, I’m all in. Let’s turn code into magic! ⚡

Location:
Bihar- Bettiah
Joined:
May 19, 2024

Bye Bye, Try-Catch Blocks: Meet JavaScript's Safe Assignment Operator Proposal😉

Publish Date: Aug 20 '24
1023 61

Introduction

JavaScript error handling is about to get a major upgrade. The new ECMAScript Safe Assignment Operator Proposal (?=) is here to streamline your code by reducing the need for traditional try-catch blocks. Let’s explore how this proposal can simplify your error management and make your JavaScript code cleaner and more efficient.

Simplified Error Handling

No More Nested Try-Catch

  • Problem: Traditional try-catch blocks often lead to deeply nested code, making it harder to read and maintain.
  • Solution: The ?= operator reduces nesting by transforming the result of a function into a tuple. If an error occurs, it returns [error, null]; otherwise, it returns [null, result].

Example:

   async function getData() {
     const [error, response] ?= await fetch("https://api.example.com/data");
     if (error) return handleError(error);
     return response;
   }
Enter fullscreen mode Exit fullscreen mode

Enhanced Readability

Cleaner, More Linear Code

  • Problem: Try-catch blocks can clutter code and disrupt the flow of logic.
  • Solution: The ?= operator makes error handling more intuitive, keeping your code linear and easy to follow.

Example:

   const [error, data] ?= await someAsyncFunction();
   if (error) handle(error);
Enter fullscreen mode Exit fullscreen mode

Consistency Across APIs

Uniform Error Handling

  • Problem: Different APIs might require different error-handling techniques, leading to inconsistencies.
  • Solution: The ?= operator introduces a consistent way to handle errors across all APIs, ensuring uniform behavior.

Improved Security

Never Miss an Error Again

  • Problem: Overlooking error handling can lead to unnoticed bugs and potential security risks.
  • Solution: By automatically handling errors in a standardized way, the ?= operator reduces the chance of missing critical errors.

Symbol.result: The Secret Sauce

Customizable Error Handling

  • Overview: Objects that implement the Symbol.result method can use the ?= operator to define their own error-handling logic.
  • Usage: The Symbol.result method should return a tuple [error, result].

Example:

   function example() {
     return {
       [Symbol.result]() {
         return [new Error("Error message"), null];
       },
     };
   }
   const [error, result] ?= example();
Enter fullscreen mode Exit fullscreen mode

Recursive Error Handling

Handle Nested Errors Like a Pro

  • Overview: The ?= operator can recursively handle nested objects that implement Symbol.result, ensuring even complex error scenarios are managed smoothly.

Example:

   const obj = {
     [Symbol.result]() {
       return [
         null,
         { [Symbol.result]: () => [new Error("Nested error"), null] }
       ];
     },
   };
   const [error, data] ?= obj;
Enter fullscreen mode Exit fullscreen mode

Promises and Async Functions

Async Error Handling Made Easy

  • Overview: The ?= operator is designed to work seamlessly with Promises and async/await, making error handling in asynchronous code straightforward.

Example:

   const [error, data] ?= await fetch("https://api.example.com");
Enter fullscreen mode Exit fullscreen mode

Using Statement Integration

Streamline Resource Management

  • Overview: The ?= operator can be used with using statements to manage resources more effectively, making cleanup easier and less error-prone.

Example:

   await using [error, resource] ?= getResource();
Enter fullscreen mode Exit fullscreen mode

Why Not Data First?

Prioritizing Error Handling

  • Overview: Placing the error first in the [error, data] ?= structure ensures that errors are handled before processing data, reducing the risk of ignoring errors.

Example:

   const [error, data] ?= someFunction();
Enter fullscreen mode Exit fullscreen mode

Polyfilling the Operator

Future-Proof Your Code

  • Overview: While the ?= operator cannot be polyfilled directly, its behavior can be simulated using post-processors to maintain compatibility with older environments.

Example:

   const [error, data] = someFunction[Symbol.result]();
Enter fullscreen mode Exit fullscreen mode

Learning from Other Languages

Inspired by the Best

  • Overview: The pattern behind the ?= operator is inspired by similar constructs in languages like Go, Rust, and Swift, which have long embraced more structured error handling.

Current Limitations and Areas for Improvement

Still a Work in Progress

  • Nomenclature: The proposal needs a clear term for objects implementing Symbol.result.
  • Finally Blocks: There’s no new syntax for finally blocks, but you can still use them in the traditional way.

For more information, visit the GitHub repository.

Conclusion

The Safe Assignment Operator (?=) is a game-changer for JavaScript error handling, promising to reduce the need for clunky try-catch blocks and make your code cleaner and more secure. Although still in development, this proposal could soon become a standard tool in every JavaScript developer’s toolkit.

Comments 61 total

  • Jon Randy 🎖️
    Jon Randy 🎖️Aug 20, 2024

    It won't be soon (if at all) - this is only a draft proposal that hasn't even been accepted for consideration yet, let alone adoption

    • leob
      leobAug 20, 2024

      Lol the "elephant in the room" - the article does not mention anything about where this proposal is documented, nor about its expected timeline ...

      "Bye Bye, Try-Catch Blocks" - that's highly premature, to put it mildly ...

      "JavaScript error handling is about to get a major upgrade" - is rather misleading ...

      P.S. and if you think critically about it for a moment, then you'll probably conclude that the advertised advantages might actually be disadvantages in the context of JS ... I see more negative views of this proposal than positive ones here:

      reddit.com/r/javascript/comments/1...

      I'm also not really convinced ...

    • Andrew Bone
      Andrew BoneAug 21, 2024

      If you look at the syntax votes ?= is not even the front runner.

      pie chart showing 'try as throw' in the lead

      (also total votes add up to 666)

    • Drew Schillinger
      Drew SchillingerAug 21, 2024

      Dang. I'm looking forward to the 101 almost-the-same-but-missing-nuanced implementations that npm packages or each framework will introduce...

  • Krzysztof
    KrzysztofAug 20, 2024

    What about this:

    const result = await myfunction()
        .catch(()=>{ 
           // handle error
        })
    
    Enter fullscreen mode Exit fullscreen mode
  • Samuel Rouse
    Samuel RouseAug 20, 2024

    This is what the title example looks like with promises.

    function getData() {
      return fetch("https://api.example.com/data").catch(handleError);
    }
    
    Enter fullscreen mode Exit fullscreen mode

    The proposal reminds me of the "nodeback" error-first callback style before the majority of the asynchronous actions adopted promises. I prefer promises, and dislike the need for try/catch blocks and async function declarations that come with await. This proposal is a better solution than try/catch blocks, but it seems to me like we're 60% of the way back to a promise chain but still with more characters and more mental parsing.

    someFunction().then().catch().finally();

    Also, there is no need for a finally equivalent with Safe Assignment because we've eliminated the scoping. You can use plain conditions.

    if (error) {
      // .catch() equivalent
    } else {
      // .then() equivalent
    }
    // .finally() equivalent
    
    Enter fullscreen mode Exit fullscreen mode

    Thank you for putting the article together. I appreciate the work on it, even if I don't like proposal. 😅

    • saad zahem
      saad zahemAug 20, 2024

      I agree with you but there is one thing though. finally block is meant to be executed regardless of whether your code succeed, get an error and handle it successfully, get an error and throw it again, or throw its own error. It is a misconception that a finally block is equivalent to the code that follows the try-catch-else block.

      if (error) {
        // .catch() equivalent
      } else {
        // .then() equivalent
        throw Error();
      }
      // This will not be executed like a finally block
      
      Enter fullscreen mode Exit fullscreen mode

      Instead, I suggest this modified solution.

      if (error) {
        // .catch() equivalent
        var errorToThrow = null;
      } else {
        // .then() equivalent
        var errorToThrow = Error();
      }
      // .finally() equivalent, executed in all cases
      if (errorToThrow !== null) throw errorToThrow;
      
      Enter fullscreen mode Exit fullscreen mode

      Finally, finally block is used to free allocated resources or to close a file so we make sure that it is not interrupted by any event.

  • 𒎏Wii 🏳️‍⚧️
    𒎏Wii 🏳️‍⚧️Aug 20, 2024

    So basically, JavaScript has found yet another way of being "kinda like Lua, except worse"?

  • Mostafa
    MostafaAug 20, 2024

    Generally handling errors in software a critical topic and I don't think what you just shared with us will be a part of Ecma

  • Techninjax
    TechninjaxAug 20, 2024

    hmmm will i say this is better or harder

  • Yogi Arif Widodo
    Yogi Arif WidodoAug 21, 2024

    can you make a real example condition for example notes app maybe :D

  • Daniel Macák
    Daniel MacákAug 21, 2024

    The title is super misleading since it makes it sound like this feature is like ECMA Stage 3 which is totally untrue. Claiming "this proposal could soon become a standard tool in every JavaScript developer’s toolkit" is very naive; just remember how much it took for Decorators to come to Stage 3, it's been an eternity.

    As for the proposal itself, yes it improves error handling in some areas but to me it looks like it makes other areas worse, like bubbling up errors would become way more manual with it.

  • ProgKids
    ProgKidsAug 21, 2024

    Awesome post!

    • dev procedure
      dev procedureAug 21, 2024

      It's a stupid proposal as ?= is confusing and Try-Catch is very straight-forward and WORKS

      • Mustafa
        MustafaAug 26, 2024

        Right?? Since the Try-Catch structure is a common way of catching errors in programming, it also improves code readability for others who read your code.

        Absolutely no need for fancy things.

  • dev procedure
    dev procedureAug 21, 2024
    Problem: Try-catch blocks can clutter code and disrupt the flow of logic.
    Solution: The ?= operator makes error handling more intuitive, keeping your code linear and easy to follow.
    
    Enter fullscreen mode Exit fullscreen mode

    100% FALSE and B.S.
    Try-Catch is straight-forward language.
    The ?= is CONFUSI(NG to begin with.

    The ?= should be canned and thrown away.
    It's look stupid and Go, Rust, and Swift, are not known to easy or that popular.
    BUt lots of HYPE...

    The ?= is just WANNBE nonsense.

  • Castric Laem
    Castric LaemAug 21, 2024

    This is obviously written by ChatGPT. The whole article screams prompt engineering and a poor attempt at making this readable. Which means the author has no idea what half of this article means.

  • Andrew Bone
    Andrew BoneAug 21, 2024

    If you're really adverse to the try/catch block you can make a helper function that does the same as the safe assignment operator. I really don't see it getting much traction unfortunately, especially seeing as it's such an easy function.

    /**
     * execute a callback and return an result/error array
     *
     * @param {callback} function to be executed
    */
    const safePromise = async (callback) => {
      try {
        const res = await callback();
    
        return [null, res]
      } catch (error) {
        return [error, null];
      }
    }
    
    // Example use
    const [error, data] = await safePromise(() => fetch("https://api.example.com"));
    if (error) handle(error);
    
    Enter fullscreen mode Exit fullscreen mode
    • BlobKat
      BlobKatAug 22, 2024

      You don't need a callback, this can be done by simply awaiting the value (Promise object)

      • JoelBonetR 🥇
        JoelBonetR 🥇Aug 22, 2024

        What you don't need is precisely await. Here's an example of this:

        /**
         * Fetch implementation details, you could do it in any different way that's suitable to your project
         */
        const fetcher = async (config: ServiceConfiguration): Promise<ServiceError | ServiceResponse> => {
          try {
            return fetch(config.target, { method: config.operation, headers: config.headers }).then((res) => res.json());
          } catch (error: RequestError) {
            return { svcError: error, ...config } as ServiceError;
          }
        };
        
        /**
         * This doesn't even need to be a "hook" it would work with a different name being a normal function.
         */
        export const useService = async (config: ServiceOperation, setter?: Dispatch<SetStateAction<ServiceResponse>>) => {
          fetcher(config).then((res) => {
            if (res?.hasOwnProperty('svcError')) return Promise.reject(res);
            else if (setter) setter(res);
            else return Promise.resolve(res);
          });
        };
        
        Enter fullscreen mode Exit fullscreen mode

        This works pretty well when loading multiple stuff at the same time so you don't block the thread on every single request by awaiting the response before continuing with the next one; meaning that you can call useService in a promise.all or promise.allSettled and expect all requests to be launched at the same time, in parallel and capture the responses seamlessly (and asynchronously as -hopefully- intended).

        This can be used along any framework, library or with Vanilla JS if you are eager to toy around with object proxies or any other methodology you prefer. This is, though, a simplification of what I have on a Next (React) project as you may have noticed by the Dispatch type hint. Following that, an usage example would be:

        const [shoppingHistory, setShoppingHistory] = useState();
        
        useEffect( () => {
          const config: ServiceOperation = getServiceConfig(); // implementation details
        
          useService(config, setShoppingHistory);
        }, [userId]);
        
        useEffect(()=>{
          console.log('shopping history has been loaded');
        }, [shoppingHistory]);
        
        Enter fullscreen mode Exit fullscreen mode

        We're coding in a "reactive" manner pretty much since Angular JS first came out (14 years ago 🤯), try to avoid breaking the asynchrony unless it's completely necessary; instead let things react to other things when they find suit, simply let it flow! 😎

        As a bonus advice, try not to use await in the same instruction where a then is present and vice-versa unless you know very well what you are doing.

        Image description

  • intrnl
    intrnlAug 21, 2024

    This is awful, I'd much prefer do expressions to come around, which would set up a precedence for try expressions

    const messages = try {
      await loadMessages(lang);
    }  catch (err) {
      reportError(err);
      await loadMessages("en");
    }
    
    Enter fullscreen mode Exit fullscreen mode

    This is a lot better than replicating Go's semantics.

    • Amjad Mohamed
      Amjad MohamedOct 14, 2024

      What about the rust like:

      const messages = await loadMessages(lang) catch (err) {
        reportError(err);
        await loadMessages("en");
      };
      
      Enter fullscreen mode Exit fullscreen mode
  • Martin Baun
    Martin BaunAug 21, 2024

    Reminds me of await-to-js, which is pretty neat in my opinion.

  • Daniel Rodríguez Rivero
    Daniel Rodríguez RiveroAug 21, 2024

    Awful. JS should find its way, rather than copying the bad implementation of good ideas (better error handling is needed but the way golang does it is awful)

  • I, Pavlov
    I, PavlovAug 21, 2024

    Does anyone really think that this

    const obj = {
         [Symbol.result]() {
           return [
             null,
             { [Symbol.result]: () => [new Error("Nested error"), null] }
           ];
         },
       };
    
    
    Enter fullscreen mode Exit fullscreen mode

    is better than nested try-catch?

    Placing the error first in the [error, data] ?= structure ensures that errors are handled before processing data, reducing the risk of ignoring errors.

    What prevents a developer from doing this:

    const [, data] ?= someFunction();
    useDataIgnoringError(data);
    
    Enter fullscreen mode Exit fullscreen mode
    • Samuel Braun
      Samuel BraunSep 21, 2024

      Not defending this solution as there are probably better ones but Symbol object keys are already what makes for loops working. It doesnt mean the developer needs to write it as it would get abstracted away just like an array abstracts away Symbol.iterator(). For the second its more clear/obvious that [, error] does something that is considered bad practice whereas [data] doesn't.

  • Ankit Rattan
    Ankit RattanAug 21, 2024

    Well! JS is now competing with Python in short syntax! 😊😁

  • Akash Kava
    Akash KavaAug 22, 2024

    If accepted, this will include nightmare in debugging, in an explicit try-catch, author and maintaner both are aware of what is happening, aim of developer is not to write short code, but maintanable code.

    If I am looking at my own code after one year, I would usually search for try keyword and investigate on it. Put a breakpoint and see what error is thrown and why. I don't think there should be any proposal which would consume an exception and return something else.

  • Guillermo Liss
    Guillermo LissAug 22, 2024

    I personally prefer this way to the try-catch. I hope eventually this becomes part of js.

  • Peter Vivo
    Peter VivoAug 22, 2024

    Until ?= operator did not pass the proposal state, this is just a fairy tale. I know good to play with proposal things, sometimes it is really worth. My favorite is the pipeline operator |> which is really missing from JS because give natural solution to chaining any one parameter function.

  • Alain D'Ettorre
    Alain D'EttorreAug 22, 2024

    Although this is very far from being implemented, I believe it could be worth it. The main problem I see is that Go enforces you to handle errors like this, the whole standard library returns multiple values with error being the second value (usually), people are encouraged to do the same and the syntax allows you to return multiple values, also no exceptions that "bubble" exist.

    JS, instead, relies on 20+ years of Exception-based programming and having an alternative like this seems a good way to fragment code once again

  • Joey Mezzacappa
    Joey MezzacappaAug 23, 2024

    That example doesn't work if error is falsy.

  • Christian Paez
    Christian PaezAug 23, 2024

    Interesting proposal, however I still prefer standard try catch blocks, to me const [error, response] seems ugly, no reason to declare those as parts of an array.

  • Rafa Rodríguez
    Rafa RodríguezAug 23, 2024

    It's still a draft. In the meantime you can do this:

    const attempt = (operation) => {
       let result = null;
       let error = null;
    
       try {
          result = operation(); 
       } catch(err) {
          error = err;
       }
    
       return [error, result];
    };
    
    const attemptAsync = async (operation) => {
       let result = null;
       let error = null;
    
       try {
          result = await operation();
       } catch(err) {
          error = err;
       }
    
       return [error, result];
    };
    
    Enter fullscreen mode Exit fullscreen mode
  • Abdul Aziz Al Basyir
    Abdul Aziz Al BasyirAug 26, 2024

    i used to

    const result = await fetch().catch(e => {});

    console.log(result)

  • Tamjid Ahmed
    Tamjid AhmedAug 26, 2024

    i n d i a n c l i c k b a i t.

    • Richard Holguín
      Richard HolguínAug 29, 2024

      From the producers of unnecessary copy/pasted Medium post, comes...

  • Mina Tom
    Mina TomAug 26, 2024

    Wow its looks amazing do i try this for my website Laptop screen repalcement because i have to write some assignments and data collections tasks for my website project. becuase these softwares help me a lot

  • sschneider-ihre-pvs
    sschneider-ihre-pvsAug 27, 2024

    You can today use a similar construct without the operator of course since js does not allow custom operators or operator overloading except in a compiler like svelte $: for example.
    The concept really resembles the Either Monad and libs like effect.website/ really push this in a good way

  • Lewis Donovan
    Lewis DonovanAug 28, 2024

    This is never getting anywhere near ECMA

  • Liem Le Hoang Duc
    Liem Le Hoang DucAug 29, 2024

    So, I'm trying to say that go error handling is such, and now seeing this on JS? Hope this proposal never get approved. Try/Catch/Finally is not evil or bad. and if (error) is such.

  • cutmasta-kun
    cutmasta-kunAug 30, 2024

    Yes, please! :3 I love this style of error handling in go.

  • Katarzyna Krawczyk
    Katarzyna KrawczykSep 2, 2024

    Looks great <3 !

  • Md Kawsar Islam Yeasin
    Md Kawsar Islam YeasinSep 3, 2024

    It's like null, error block of GO

  • Amirreza Farzan (jexroid)
    Amirreza Farzan (jexroid)Sep 4, 2024

    it seems like javascript is learning something from GO:

    file, err := os.Create(filepath.Join(projectPath, ".air.toml"))
        if err != nil {
            return err
        }
    
    Enter fullscreen mode Exit fullscreen mode

    golang doesn't support try-catch blocks at all.

  • Alexander Antonyuk
    Alexander AntonyukSep 7, 2024

    Sweet!

    I like this approach, like in Golang.

  • Najmus Sakib
    Najmus SakibSep 16, 2024

    Misleading title

  • Ashikur Asif
    Ashikur AsifSep 16, 2024

    ট্রাই ক্যাচ ব্লক কি তুমার নুনুতে কামড় দিছে নাকি?

  • Ali Raza
    Ali RazaSep 27, 2024

    The ?= operator is not a direct replacement for try...catch in JavaScript.
    While ?= offers a concise way to handle null or undefined values, it doesn't provide the same error-handling capabilities as try...catch.
    Here's a breakdown of their key differences:
    ?= Operator:

    • Purpose: Handles null or undefined values in expressions.
    • Syntax: variable ?= expression
    • Behavior: Assigns expression to variable only if variable is null or undefined.
    • Use cases: Default values, conditional assignments, avoiding null reference errors. try...catch Block:
    • Purpose: Catches and handles exceptions that occur during code execution.
    • Syntax:
      try {
      // Code that might throw an exception
      } catch (error) {
      // Code to handle the exception
      } finally {
      // Optional code that always executes, regardless of exceptions
      }

    • Behavior: Executes the code within the try block. If an exception occurs, the catch block is executed with the exception object as an argument. The finally block (if present) is always executed, even if an exception is thrown.

    • Use cases: Handling runtime errors, preventing program crashes, providing graceful error recovery.
      Key Points:

    • ?= is primarily for handling null or undefined values, while try...catch is for handling a broader range of exceptions.

    • ?= is more concise and often preferred for simple null checks, but try...catch is essential for more complex error handling scenarios.

    • Combining ?= with other techniques like optional chaining (?.) can help mitigate null reference errors in many cases.

  • Dave Mcsavvy
    Dave Mcsavvy Sep 28, 2024

    Sounds like a cool feature ✨

  • XPD
    XPDOct 1, 2024

    2 nd proposal is better. Has more votes. Since ?= is syntactic sugar, keywords are better than operator overload to reduce conflict and changing core language.

  • Junior Jboy
    Junior JboyOct 13, 2024

    Cach block

  • ivkeMilioner
    ivkeMilionerOct 24, 2024

    This is a clickbait text that is false and has already been debunked 100 times.

  • Juliano
    JulianoNov 25, 2024

    Nice post. You can currently do something similar for promises with Promise.allSettled([promise]).map(r => r.status === 'fulfilled' ? [null, r.value] : [r.reason,null])[0]

  • Aral Roca
    Aral RocaNov 25, 2024

    A good hack:

    Image description

  • Reid Burton
    Reid BurtonMar 2, 2025

    This NEEDS to go through. Who's with me?

Add comment