The two main ways of interfacing with threaded LibLoading that I see are callbacks or some kind of future object. Possible example code which each could be as follows:
future = logic.LibLoad('foo.blend', 'Scene', async=True)
One advantage to callbacks is that LibLoad() will never return anything as opposed to sometimes returning an object if certain keywords are used. This helps keep things consistent. Also, there have been some plans to add other callbacks to the BGE, so a callback for LibLoad() keeps things consistent there too.
logic.LibLoad('foo.blend', 'Scene', async=True, async_callback=do_something)
However, with future objects, they allow a clear path for future extensions. For example, it could be possible to add some sort of percentage counter to the future object (I have yet to evaluate the feasibility of this though). I guess optional arguments could be added to the callback for things like percentage:
And if the callback doesn't have an argument, it would only be called when the libload is done.
if percent == 100:
print("Level is %.0f%% loaded...")
logic.LibLoad('level.blend', 'Scene', async=True, async_callback=load_level)
And one last thought, as a potential shortcut, if async_callback is specified and async is not, should async default to True?
Feedback would be much appreciated!
Overall, I'm leaning more toward a callback myself.