What is easy to think of is the problem of asynchronous expiration: imagine that the first-level menu changes, triggering the pull of the second-level menu content, but the network speed is slow, and the process takes 3 seconds. After 1 second, the user changes the first-level menu again, triggering the pull of the content of the second-level menu again. At this time, the network speed is faster, the data is returned after 1 second, and the second-level menu is re-rendered; but 1 second later, the first-level menu is re-rendered. The result of this request is returned, and the second-level menu is rendered again. However, in fact, the first-level menu has changed since then, and the content has expired. This rendering is wrong. We can use closures to perform data expiration checking.
What is not easy to think of is the problem of synchronous expiration (actually it is also asynchronous, but without io interaction, it is a timeout function with a buffer time of 0), that is, due to the existence of the event queue, it may occur if you are not careful. After expiration, there will be relevant comments in the code.
As the author said, it is a timeout function with a buffer time of 0. If the update of the first-level menu to the second-level menu is written in the setTimeout() function, it is an asynchronous operation. It will also happen that subsequent operations update the interface first, and the results of the previous operations expire.