The fact that coroutine.yield() happens to work shouldn't be relied upon. It's a race condition. Both addons and scripts run in isolated threads, yielding returns control back to the scheduler which notifies the calling function (in this case the script loader) that excecution has stopped, and then schedules the coroutine to be resumed at a later time. Depending on the timing this opens a small window for the script loader to send a request to the scheduler to stop, and once that happens the lua interpreter is torn down. I think, due to another quirk with how unloading happens, that execution will always continue after the first call to coroutine.yield(), but after that it's up to the whims of the OS. The fact that it works once is definitely an implementation detail that is subject to change at any time.
Making yield and sleep work correctly in scripts requires fairly drastic changes to the way they are run. To understand why, it may help to know that when scripts were first implemented, sleep had yet to be implemented, and it was not possible to yield from scripts or from the global scope in an addon at all (doing so caused a runtime error). The only reason you can call either function now without error, is because the addon framework (which scripts are implemented on top of) was modified so that yielding from global scope worked.
Also yes, while events can be registered in scripts (they're implemented on top of the addon framework after all), the events will never be called because the script gets unloaded before they ever get a chance to run.