Depending on which board/port you're using, MicroPython does support threading, via the _thread module. However, I'd recommend against using it as threading is almost always more problematic than useful.
My recommendation is to use asyncio. The latest version of MicroPython (v1.13) includes a much-improved version of asyncio, and you can see Peter's excellent tutorial and guides here
https://github.com/peterhinch/micropython-async
In general though, for embedded systems the approach you need to take is that IRQs and event handlers should only be used to tell your code that something happened and they should do the minimal work possible to record the event (i.e. set a global variable flag or something). Then your main program should be looking at these variables to decide what to do.