How to Think About Async Ports
The best way to think about the async port model to consider it similar to the model used for REBOL/View. It is event driven. This approach takes advantage of the fact that most computer programs are waiting most of the time for user interaction or IO to happen (of course there are exceptions, see below).
For example, in /View you write:
window: layout [ h1 "My Window" btn "Button" [print "button1"] btn "Quit" [quit] ] view window
But, that last line is actually the same as:
view/new window ; open the window, do not wait do-events ; wait for events
DO-EVENTS is simply a call to the WAIT function that will not return until the last window is closed. As window events happen, the view system calls the VID system and events are sent to the interface objects defined above.
This is an event driven method of programming. Like Hypertalk (Apple Hypercard) or Lingo (Macromedia) languages, the "flow" depends on the events that occur. In REBOL you have the choice of writing either "linear" code that executes in sequence like most programming languages or event driven code such as that shown above.
Note that when you write code like the above, it begins in linear mode as you define all the functions and actions of the program. This can be thought of as your setup or initialization phase. During this time, the sequence of execution will not be interrupted. Only when you finally call WAIT (directly or indirectly) the system becomes event driven (asynchronous).
In the new REBOL kernel, the event driven model also works with network ports. So, in addition to your view code, you can easily create network connections during your linear setup code (or actually at any time) and they will also be processed once you call WAIT.
window: layout [ h1 "My Window" btn "Button" [print "button1"] btn "Quit" [quit] ] view/new window ; open the window handler: func [port action arg] [ ... your handler code ... ] server-port: open/direct/binary/async url :handler ... other setup ... do-events
At that point your code becomes event driven and both the GUI and the async ports will be processed.
Here are some important things to note about this mode of operation:
Also note that your program may return from the WAIT or DO-EVENTS that is shown above. Errors will cause it to return and closing the main window will cause it to return. A well written program needs to handle those cases. For example, you can deal with errors like this:
... above setup code ... if error? err: try [do-events][ show-error disarm :err ] ... additional cleanup code ...
Here the SHOW-ERROR function may open a new window to report the error to the user. If you want the program to continue, even after the error occurred, you can put a loop around this part. If you do that it is wise to add an error counter for the case where continuing from the error situation is not possible:
loop 3 [ either error? err: try [do-events][ show-error disarm :err ][ break ; normal exit ] ]
Keep in mind that an error can be thrown from a point in your code where state changes (e.g. setting variables, modifying lists) related to your functions has not been concluded. Everything that follows the error point has been left undone.
AltME and other products serve as a good example of this kind of error "capture" and processing. In AltME's case the error is displayed and the user has the option of sending it directly to SafeWorlds bug database.