The standard way of dealing with this kind of scenarios is to use .Sync method of the Page (or in some cases Browser) objects.
I found it very temperamental and depending on the tested application this function might work perfectly and on the other occasion will not wait long enough.
The problem seems to be related mainly to Web 2.0 applications (AJAX based). Web page connection to the server is usually closed much earlier then asynchronous connection opened by java script.
If there is a visual guide indicating that that page is still loading you could write a loop and check for that object. Once the object disappear you could resume test execution.
To save yourself writing this code in every place where you need to sync you could overwrite QTP native method with your own version with following code:
RegisterUserFunc "Page", "Sync", "SyncToPage"
Function SyncToPage(oPage)
'Call native function first'
oPage.Sync
'Custom sync code'
End Function
Thanks,
Maciej