Both methods work just fine and there is a choice of approach. Recently, my personal choice for implementing this kind of functionality is to use Sam’s approach and it’s mostly due to the user experience. Using this approach, the code is called directly and there is no time spent by the browser needing to load a new blank page only to return to the same page. It works much more seamlessly. You also get the benefit of having less objects to develop (no VF page) and tie together. The only real downside (outside of requirement-specific ones) is that Salesforce won’t bark at you if you delete the web service class because it doesn’t know that the web service is tied to JavaScript. If your Apex Code is a controller for your VF page, Salesforce will protect you from deleting it accidentally.

Danny Walker Said,

The downside to this method is that it doesn’t allow you to return a PageReference. I’m trying to construct a wizard that starts on a different page depending on what values are required for the current task.