Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to understand callback function

2025-03-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly introduces "how to understand callback function". In daily operation, I believe many people have doubts about how to understand callback function. The editor consulted all kinds of data and sorted out simple and easy-to-use operation methods. I hope it will be helpful for you to answer the doubt of "how to understand callback function"! Next, please follow the editor to study!

It all starts with such a need.

Suppose your company is going to develop the next generation of national App "Youtiao of tomorrow", an App that focuses on solving the national breakfast problem. In order to speed up the development process, this application is jointly developed by A team and B team.

One of the core modules is developed by team An and then called by team B. this core module is encapsulated into a function called make_youtiao ().

If the make_youtiao () function executes quickly and returns immediately, then the students in Group B only need:

Hongmeng official Strategic Cooperation to build HarmonyOS Technology Community

Call make_youtiao ()

Wait for the function execution to complete

Continue the follow-up process after the function is executed

From the perspective of program execution, the process looks like this:

Hongmeng official Strategic Cooperation to build HarmonyOS Technology Community

Save the context of the currently executed function

Start executing the function make_youtiao ()

After the execution of make_youtiao (), the control goes back to the calling function

If all the functions in the world are as simple as make_youtiao (), there is a good chance that programmers will lose their jobs. Fortunately, the world of programs is complex, so that programmers have the value of existence.

Reality is not easy.

In reality, the make_youtiao () function has a huge amount of data to deal with, assuming that there are 10000, then make_youtiao (10000) will not return immediately, but may take 10 minutes to complete and return.

What should you do at this time? Think about it.

Some students may ask, can't it be called directly as just now? it's so simple.

Yes, there is no problem with this, but as Einstein said, "everything should be as simple as possible, but not too simple."

Think about what's wrong with a direct call?

Obviously, if it is called directly, the calling thread will be blocked and paused and wait 10 minutes before it can continue to run. During these 10 minutes, the thread will not be assigned CPU by the operating system, which means that the thread will not get any push.

This is not an efficient approach.

No programmer wants to stare at the screen for 10 minutes to get the result.

So is there a more efficient approach?

Think of the boss in our previous article who was watching you write code (see "from rookie to master, you need to understand synchronization and async"), we already know that this mode of waiting until another task is completed is called synchronization.

If you were the boss, would you do nothing and watch your employees write code? So a better way is for the programmer to do what the boss should do when the code is written, and the programmer will naturally inform the boss after writing it, so that neither the boss nor the programmer has to wait for each other. This mode is called asynchronism.

Going back to our topic, a better way here is to call the make_youtiao () function and no longer wait for the function to complete, but instead go back to the subsequent process, so that the program of team A can run at the same time as the make_youtiao () function, like this:

In this case, the callback must come out.

Why do we need to call back callback

Some students may not understand why a callback is needed in this situation. Don't worry, let's talk about it slowly.

Suppose the first edition of our "Youtiao tomorrow" App code reads like this:

Make_youtiao (10000); sell ()

You can see that this is the simplest way to write, the meaning is very simple, make Youtiao and sell it.

We already know that since the function make_youtiao (10000) doesn't return for 10 minutes, and you don't want to stare at the screen for 10 minutes and wait for the result, a better way is to let the make_youtiao () function know what to do after making Youtiao, that is, a better way to call make_youtiao is like this: "make 10000 Youtiao, fried and sell", so calling make_youtiao changes like this:

Make_youtiao (10000, sell)

See, now make_youtiao this function has one more parameter, in addition to specifying the number of Youtiao production, you can also specify what to do after production, the second function called by the make_youtiao function is called callback, callback.

Now you can see that although the sell function is defined by you, this function is called and executed by other modules, like this:

How is the make_youtiao function implemented? it's simple:

Void make_youtiao (int num, func call_back) {/ / make Youtiao call_back (); / / execute callback}

In this way, you don't have to stare at the screen, because you tell the make_youtiao function what to do after the make_youtiao function is executed, and the function knows what to do after making Youtiao, which liberates your program.

Some students may still have questions: why doesn't the group writing make_youtiao directly define the sell function and then call it?

Don't forget that the Youtiao App of tomorrow will be developed by both team An and team B. how will team A know how team B will use this module when writing make_youtiao? assuming that team A really defines its own sell function, it will write like this:

Void make_youtiao (int num) {real_make_youtiao (num); sell (); / / execute callback}

At the same time, the module designed by Group An is very easy to use, so team C also wants to use this module, but team C's need is to make Youtiao and put it in the warehouse instead of selling it directly.

Void make_youtiao (int num) {real_make_youtiao (num); if (Team_B) {sell (); / / execute callback} else if (Team_D) {store (); / / put it in warehouse}}

The story is not over, suppose Group D wants to use it again, should we continue to add if else? In this way, the students in Group An only need to maintain the make_youtiao function to achieve a full workload, which is obviously a very bad design.

So as you can see, what to do next after making Youtiao is not a concern for team An implementing make_youtiao, and obviously only the user who calls make_youtiao knows.

Therefore, team An of make_youtiao can completely hand over what to do next to the caller through the callback function. Students in group An only need to program the abstract concept of callback function, so that callers can do whatever they want to do after making Youtiao, whether they sell it, put it in inventory, eat it, and so on. Group A's make_youtiao function does not have to make any changes at all. Because team An is programming against the abstract concept of callback functions.

That's what callback functions do, and of course that's the power of the idea of programming against abstractions rather than concrete implementations. Polymorphism in object-oriented is essentially something you use to program against abstractions rather than implementations.

Asynchronous callback

This is not the end of the story.

In the above example, although we use the concept of callback, that is, the caller implements the callback function and then passes the function as an argument to other module calls.

However, there is still a problem here, that is, the way the make_youtiao function is called is still synchronous. About synchronous and asynchronous please, that is to say, the caller is implemented in this way:

Make_youtiao (10000, sell); / / nothing can be done until the make_youtiao function returns

We can see that the caller must wait for the make_youtiao function to return before continuing with the subsequent process. Let's take a look at the implementation of the make_youtiao function:

Void make_youtiao (int num, func call_back) {real_make_youtiao (num); call_back (); / / execute callback}

You see, since we have to make 10000 Youtiao, the execution of the make_youtiao function takes 10 minutes, that is, even if we use callbacks, the caller does not need to care about the subsequent process after Youtiao production, but the caller will still be blocked for 10 minutes, which is the problem with synchronous calls.

If you really understand the previous section, you should be able to think of a better way.

Yes, that's asynchronous invocation.

Anyway, the subsequent process after the production of Youtiao is not the concern of the caller, that is to say, the caller does not care about the return value of the function make_youtiao, then a better way is to put the task of making Youtiao to another thread (process), or even another machine.

If it is implemented in a thread, then make_youtiao is implemented like this:

Void make_youtiao (int num, func call_back) {/ / execute processing logic create_thread (real_make_youtiao, num, call_back) in a new thread;}

See, when we call make_youtiao, we will return immediately. Even if the production of Youtiao has not really started, and the caller does not need to wait for the process of making Youtiao, the post-process can be executed immediately:

Make_youtiao (10000, sell); / / return immediately / / execute the subsequent process

At this time, the follow-up process of the caller can be carried out at the same time as the production of Youtiao, which is the asynchronous call of the function, of course, this is also the efficiency of asynchronous.

A new programming mode of thinking

Let's take a closer look at the process again.

The most familiar mindset for programmers is as follows:

Call a function to get the result

Process the obtained results

Res = request (); handle (res)

This is the synchronous call of the function. Only after the request () function returns the result can the handle function be called for processing. Before the request function returns, we must wait. This is the synchronous call. The control flow is like this:

But if we want to be more efficient, then we need to call asynchronously, instead of calling the handle function directly, we pass it to request as an argument:

Request (handle)

We don't care when request actually gets the result, this is what request should care about, we just need to tell request what to do after getting the result, so the request function can return immediately, and the real processing of getting the result may be done on another thread, process, or even another machine.

This is an asynchronous call, and its control flow looks like this:

From the perspective of programming thinking, there is a big difference between asynchronous invocation and synchronization. If we treat the processing flow as a task, then we implement the whole task in synchronization. However, the task processing flow in the asynchronous case is divided into two parts:

Hongmeng official Strategic Cooperation to build HarmonyOS Technology Community

The first part is what we deal with, that is, the part before calling request.

The second part is not handled by us, but by other threads, processes, or even another machine.

We can see that because the task is divided into two parts, the call to the second part is out of our control, and only the caller knows what to do, so the callback function is a necessary mechanism in this case.

In other words, the essence of the callback function is "only we know what to do, but we don't know when to do it, only other modules know, so we have to encapsulate what we know as a callback function to tell other modules."

Now you should be able to see the difference between the programming mode of asynchronous callback and synchronization.

Next, let's give a more academic definition of callback.

Formal definition

In computer science, a callback function is a piece of executable code that is passed to other code in the form of parameters.

This is the definition of the callback function.

A callback function is a function, no different from other functions.

Note that the callback function is a software design concept that has nothing to do with a programming language, and almost all programming languages can implement callback functions.

For general functions, the functions we write will be called within our own programs, that is, we are the ones who write the functions and the callers are ourselves.

But the callback function is not like this. Although the function writer is us, the function caller is not us, but the other modules we refer to, that is, the third-party library. We call the function in the third-party library and pass the callback function to the third-party library. The function in the third-party library calls the callback function we wrote, as shown in the figure:

The reason why we need to assign a callback function to the third-party library is because the writer of the third-party library does not know what to do after certain nodes, such as the completion of Youtiao, the receipt of network data, the completion of file reading, etc., which are known only by the user of the library, so the writer of the third-party library cannot write code for the specific implementation, but can only provide a callback function to the outside world. The user of the library implements the function, and the third-party library can call the callback function at a specific node.

Another point worth noting is that we can see from the figure that the callback function is in the same layer as our main program, and we are only responsible for writing the callback function, but we are not here to call it.

Finally, it is worth noting that the callback function is called at the time node, and the callback function is only called at certain nodes, such as the completion of Youtiao production, the receipt of network data, the completion of file reading, and so on. These are all events, that is, event. In essence, the callback function we wrote is used to deal with event, so from this point of view, the callback function is nothing more than event handler. So callback functions are naturally suitable for event-driven programming event-driven, and we'll return to this topic again in a later article.

Type of callback

We already know that there are two types of callbacks, and the difference between these two types of callbacks lies in the time when the callback function is called.

Note that the concepts of synchronization and asynchronism will be used next. Students who are not familiar with these two concepts can refer to the previous article "from rookie to master, you need to understand synchronization and async".

Synchronous callback

This kind of callback is commonly referred to as synchronous callback synchronous callbacks, some call it blocking callback blocking callbacks, or there is no modification, that is, callback, callback, which is the most familiar callback method.

When we call a function An and pass in the callback function as an argument, the callback function will be executed before A returns, that is, our main program will wait for the callback function to complete, which is called synchronous callback.

There is a synchronous callback, there is an asynchronous callback.

Asynchronous callback

Unlike synchronous callback, when we call a function An and pass in the callback function as an argument, function A will return immediately, that is, function A will not block our main program, and the callback function will begin to be executed after a period of time. At this time, our main program may be busy with other tasks, and the execution of the callback function and the running of our main program will be carried out at the same time.

Since the execution of our main program and callback function can occur at the same time, in general, the execution of the main program and callback function is located in different threads or processes.

This is the so-called asynchronous callback, asynchronous callbacks, and some sources call it deferred callbacks, the name is very vivid, delayed callback.

We can also see from the above two figures that asynchronous callbacks can make better use of machine resources than synchronous callbacks. The reason is that in synchronous mode, the main program is "lazy" and pauses because other functions are blocked. However, asynchronous calls do not have this problem, and the main program will run forever.

As a result, asynchronous callbacks are more common in I _ hand O operations and are naturally suitable for high concurrency scenarios such as Web services.

Programming thinking mode corresponding to callback

Let's summarize the differences between the callback and the conventional programming mindset in a few simple sentences. Suppose we want to deal with a task that depends on a service S, we can divide the processing of the task into two parts, the part PA before invoking service S and the part PB after invoking service S. In normal mode, both PA and PB are executed by the service caller, that is, we execute the PA part ourselves and wait for service S to return before executing the PB part. But it's different in a callback. In this case, we will execute the PA section ourselves, and then tell the service S: "execute the PB section when you have finished the service." So we can see that a task is now accomplished by different modules. That is, the regular mode: after invoking the S service, I perform the X task, and the callback mode: after invoking the S service, you then execute the X task, where X is set by the service caller, and the difference lies in who will execute it.

Why asynchronous callbacks are becoming more and more important

In synchronous mode, the service caller will be blocked and paused for service execution, which will cause the whole thread to be blocked, so this programming method is naturally not suitable for high concurrency scenarios with hundreds of thousands of concurrent connections. Async is actually more efficient for high concurrency scenarios, for the simple reason that you don't have to wait in place, so you can make better use of machine resources. And the callback function is an indispensable mechanism under asynchronism.

Callback to hell, callback hell

Some students may think that with the asynchronous callback mechanism to cope with all high concurrency scenarios, you can rest easy. In fact, there is no technology in computer science that can sweep all diseases, not now, nor will it be in the foreseeable future, everything is the result of compromise. So what's wrong with the asynchronous callback mechanism? In fact, we have seen that the mechanism of asynchronous callback is different from the synchronous mode that programmers are most familiar with, and it is not as understandable as synchronization, but if the business logic is relatively complex, for example, when we deal with a task, we need to call not only one service, but several or even a dozen, if these service calls are handled in the way of asynchronous callback, then it is very likely that we will fall into the callback hell. For example, suppose we need to invoke four services to handle a task, each of which depends on the result of the previous service, which might look like this if implemented synchronously: a = GetServiceA ()

B = GetServiceB (a); c = GetServiceC (b); d = GetServiceD (c)

The code is clear and easy to understand. We know that asynchronous callbacks will be more efficient, so what would it be like to write using asynchronous callbacks? GetServiceA (function (a) {

GetServiceB (a, function (b) {GetServiceC (b, function (c) {GetServiceD (c, function (d) {.... });)

I don't think there is any need to emphasize any more. Which of these two writing methods do you think is easier to understand and the code is easier to maintain? Bloggers are lucky enough to have maintained this type of code, and I have to say that every time they add new features, they want to be transformed into two parts, one having to reread one side of the code, and the other scolding himself about why he chose to maintain the project in the first place. Asynchronous callback code can fall into a callback trap without paying attention, so is there a better way to combine the efficiency of asynchronous callbacks and the ease of reading of synchronous coding? Fortunately, the answer is yes, and we will explain this technique in more detail in subsequent articles.

At this point, the study of "how to understand the callback function" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report