Backbone应用启动前发送认证请求的异步执行问题求助
Hey there! I’ve run into this exact async authentication snag with Marionette apps before—let’s break down why it’s happening and how to fix it.
The Root Cause
Your problem boils down to the asynchronous nature of Ajax requests: your Marionette application finishes initializing (and firing off controller methods like show) before the /login authentication request returns. That’s why current_user is unavailable when your controllers run, and it affects all controllers across the app.
Solutions to Wait for Authentication Before App Startup
1. Wrap App Initialization in the Auth Request Callback
The simplest fix is to delay all core app setup (regions, controllers, routers, startup) until the authentication request successfully completes. Here’s how to adjust your CoffeeScript code:
app = do (Backbone, Marionette) -> App = new Marionette.Application() # First, fire off the authentication request $.ajax url: '/login' type: 'GET' # Adjust to your actual auth method (POST, etc.) success: (userData) -> # Set up your current_user once the response comes back App.current_user = new Backbone.Model(userData) # Now initialize your app's core structure App.addRegions mainRegion: '#main-region' # Define your controllers (now safe to use current_user) App.Controllers.Main = Marionette.Controller.extend show: -> # You can safely access App.current_user here! console.log "Authenticated user:", App.current_user.get('email') # Add your view rendering or other logic here # Set up your router App.router = new Marionette.AppRouter controller: new App.Controllers.Main() appRoutes: '': 'show' # Your root route # Start the app and kick off Backbone history App.start() Backbone.history.start() error: (xhr) -> # Handle authentication failure (e.g., redirect to login page) console.error("Authentication failed:", xhr.responseText) window.location.href = '/login' App
2. Use Promises for Cleaner Async Flow
If you prefer a more modern, maintainable approach, wrap your authentication request in a Promise. This makes the async logic easier to read and extend as your app grows:
app = do (Backbone, Marionette) -> App = new Marionette.Application() # Wrap auth request in a Promise authenticate = -> new Promise (resolve, reject) -> $.ajax url: '/login' type: 'GET' success: (userData) -> resolve(userData) error: (xhr) -> reject(xhr) # Run auth, then initialize app authenticate() .then (userData) -> App.current_user = new Backbone.Model(userData) # Initialize app regions, controllers, routers App.addRegions mainRegion: '#main-region' App.Controllers.Main = Marionette.Controller.extend show: -> console.log "Current user ready:", App.current_user.toJSON() # Your controller logic here App.router = new Marionette.AppRouter controller: new App.Controllers.Main() appRoutes: '': 'show' App.start() Backbone.history.start() .catch (xhr) -> console.error("Auth failed:", xhr) window.location.replace('/login') App
Key Notes to Avoid Future Issues
- Delay Router Initialization: Never set up your routers or start
Backbone.historyuntil after authentication completes—this prevents routes from triggering beforecurrent_useris available. - Reusable Auth Module: For larger apps, extract the authentication logic into a separate module (e.g.,
App.Auth) to keep your main app file clean and organized. - Handle Edge Cases: Make sure to account for authentication failures (like expired sessions) by redirecting to a login page or showing a user-friendly error message.
内容的提问来源于stack exchange,提问作者Manwal

