From the Apple Push Notification Service documentation:
Each device establishes an accredited and encrypted IP connection
with APNs and receives notifications over this persistent connection.
This means it uses some sort of socket-based persistent connection. It could be its own proprietary protocol, or WebSocket, etc. The "periodic actions" you're asking about are usually implemented in these protocols at the lowest level possible using TCP/IP sockets and are being constantly polled for new data on the socket. When the data is finished being read off the socket, an event is fired off to go perform some action such as display a notification on the device.
To further explain, the way sockets work is your device makes a connection to a remote server, the remote server pushes data to your device and gets put into the socket's buffer, then your device reads the socket's buffer and does something with the data. The moment the data gets pushed to your device, your device will process it. This is because your device is checking for new data on the socket's buffer all the time. It tries to read data, and if it gets data, it sends it off to get processed and then tries to read data again; if it ever doesn't get data, it just tries to read data again - forever. If the connection to the remote server ever gets disconnected, it just tries to connect again until it succeeds.
The code documentation I linked earlier is taken from Boost's ASIO library which is widely used for sockets in C++. It's implementation and usage can be simplified as follows:
01 start program
02 try to connect to server by using a socket
03 if not connected to server, goto 02
04 try to read data on socket
05 if data was read, process data
06 goto 03
In step 03
above, the device knows when you're offline and won't attempt to connect again until you get back online (the device sends out an event when you connect to the internet, so it will all happen instantly).
When no data was read in step 04
above, it immediately tries to read it again without waiting (assuming you're still connected to the server). It takes a very small amount of processing power to repeatedly try to read data on the socket, so there's no need to worry about battery or wasted resources (see @malhal's answer here for a better explanation on this and also how it works when the device is sleeping).