Why this function doesn’t works without the_post?

I’m just going to quote a brief, yet comprehensive, comment on the official reference page for the_post():

Function the_post() checks whether the loop has started and then
sets the current post by moving, each time, to the next post in
the queue.

Additionally, the “current post” here refers to the current item in WP_Query::$posts which is an array of posts returned by the WordPress query.

So for example, if WP_Query::$posts contains 5 items, the first call to the_post() will move the array pointer to the first item in that array, i.e. WP_Query::$posts[0]. Then the next calls move the pointer to WP_Query::$posts[1], WP_Query::$posts[2] and so forth until the last item is reached.

So the_post() indeed doesn’t display or even return anything, but without calling that function, you’d be stuck in an infinite while execution — for as long as the have_posts() returns true (i.e. there is a next item in WP_Query::$posts), hence as you’ve seen it, the page breaks.

And one more thing you should know, is that the current post is referenced by the global $post variable which is relied upon by the_title(), the_content(), get_the_title() and other the_ and get_the_ functions which display or retrieve/use data from the current post.