skip to Main Content

For a function that takes a callback function as an argument but also has a return value, can I get both the callback function argument and the function return value outside the function?

Here is a concrete example. Suppose we have func_a as follows.

function func_a(callback:(arg:string)=>void){
  callback("callback arg")
  return "func_a return"
}

My question is, is it possible to extract both the callback function argument,"callback arg" and the function return value "func_a return" outside func_a?

As shown in the following code, Promise and then can be used to retrieve the arguments of the callback function, but not the return value of func_a.

new Promise<string>(
  (resolve)=>{
    const func_a_return=func_a((arg)=>resolve(arg))
  }
).then((arg)=>{console.log(arg)})

This question about onSnapshot of firestore because I wanted to retrieve both the callback function argument snapshot and the function return value unsubscribe outside onSnapshot.

3

Answers


  1. Chosen as BEST ANSWER

    Thanks to tricot's answer, all my questions have been solved. Here I will try to write a complete answer to my question based on the answer.

    First of all, onSnapshot calls callback asynchronously. So for my func_a to simulate the behavior of onSnapshot, my first code example needs to be changed as follows.

    function func_a(callback:(arg:string)=>void){
      setTimeout(
        callback.bind(null,"callback arg"),
        1000
      )
      return "func_a return"
    }
    

    Receiving both the callback function argument and the function return value outside of the function can be done with the following code.

    type CallbackArgAndFunctionReturn={
      callback_arg:string,
      function_return:string
    }
    
    new Promise<CallbackArgAndFunctionReturn>(
      (resolve)=>{
        const func_a_return=func_a(
          (arg)=>resolve({
            callback_arg:arg,
            function_return:func_a_return
          })
        )
      }
    ).then((arg_return)=>{
      console.log(arg_return.callback_arg)
      console.log(arg_return.function_return)
    })
    

    Since the callback function is executed asynchronously after the function returns its value, the return value is available inside the callback function; this provided a way to get both of the values, from which I wrote the code above.

    This allows me to do what I wanted to do with onSnapshot. For example, in React, I can separate the unsubsribe function and snapshot outside of onSnapshot as follows.

    export default function Home(){
      const [myUnsubscribe,setMyUnsubscribe]=useState<Unsubscribe|undefined>()
      const GetCity=()=>new Promise<SnapshotUnsubscribe>((resolve)=>{
        const unsubscribe = onSnapshot(
          doc(db, "cities", "SF"),
          (snapshot)=>resolve({ snapshot, unsubscribe })
        )
      })
      
      useEffect(
        ()=>{
          GetCity().then(({snapshot, unsubscribe})=>{
            setMyUnsubscribe(unsubscribe)
          })
          return ()=>{myUnsubscribe && myUnsubscribe()}
        },[]
      )
    
      return <div></div>
    }
    

    Next, I will also show an answer to my question about the first code example where the callback function is executed before the function returns a value.

    Since the function returns the value after the callback function executed, the return value won't be assigned if resolved immediately in the callback function. Therefore, as shown in the following code, we should wait asynchronously in the callback function before resolve.

    function func_a(callback:(arg:string)=>void){
      callback("callback arg")
      return "func_a return"
    }
    
    type CallbackArgAndFunctionReturn={
      callback_arg:string,
      function_return:string
    }
    
    new Promise<CallbackArgAndFunctionReturn>(
      (resolve)=>{
        const func_a_return=func_a((arg)=>{
          setTimeout(
            ()=>{
              resolve({
                callback_arg:arg,
                function_return:func_a_return
              })
            },
            1000)
        })
      }
    ).then((arg_return)=>{
      console.log(arg_return.callback_arg)
      console.log(arg_return.function_return)
    })
    

  2. I’m not sure what you’re looking for. But maybe it will help you:

    function func_a(callback:(arg:string)=>number){
      callback("callback arg")
      return "func_a return"
    }
    
    type Callback = Parameters<typeof func_a>[0]; // (arg:string)=>number
    type ReturnCb = ReturnType<Callback>; // number
    

    typescript playground

    Login or Signup to reply.
  3. This question about onSnapshot of firestore because I wanted to retrieve both the callback function argument snapshot and the function return value unsubscribe outside onSnapshot.

    Contrary to the example of func_a, onSnapshot will not call the callback synchronously, which means that first onSnapshot returns the unsubscribe function, and only when the execution reaches an empty call stack, will the callback get a chance to run.

    This means, that the unsubscribe function will be available to you in the callback function, so you can do something like this:

    const unsub = onSnapshot(doc(db, "cities", "SF"), (doc) => {
        unsub();
        // Use `doc` here, or call a function here to which you pass `doc`.
    });
    

    If however you were hoping to get access to doc right after the onSnapshot function returns, you’re out of luck. The callback hasn’t run yet, so doc isn’t available yet.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search