如何在Node.js面向对象项目中正确使用Promise并优化架构
Hey Maxime! Great to see you bringing your PHP OOP experience over to Node.js—let's tackle your questions and get you set up with a solid structure and working code.
Your setup is a solid starting point, but we can refine it to align with Node.js ecosystem standards for maintainability:
- Entry point:
app.jsas the main entry is totally fine. - Controllers vs Routes: Keep route definitions in
/routes, but move your business logic classes to a dedicated/controllersfolder. This separates endpoint mapping from request handling logic (a common Node.js pattern). - Model/Class files: Don’t put these in
public/javascript—that folder is for frontend static assets (like client-side JS/CSS). Instead, create a/modelsfolder for your Sequelize models and data access classes (like yourUserclass). - Recommended structure example:
project-root/ ├── app.js # Entry point: sets up server, middleware, and routes ├── controllers/ # Classes handling request/response logic ├── models/ # Sequelize models + database access methods ├── routes/ # Route definitions mapping endpoints to controllers ├── config/ # Database/configuration files └── node_modules/ # Dependencies
The core issue you’re facing is misunderstanding how Sequelize handles Promises—methods like findAll() already return Promises, so you don’t need to wrap them in a new Promise unless you have extra logic to add. Let’s fix this with concrete examples:
Step 1: User Model/Class (in /models/User.js)
This class will encapsulate all user database operations:
const { Model, DataTypes } = require('sequelize'); const sequelize = require('../config/database'); // Path to your Sequelize config class User extends Model { // Static method to fetch all users static getAllUsers() { // Sequelize's findAll() returns a Promise—just return it directly! return this.findAll({ // Add options like attributes, filters, or includes here }); } // Add other methods like createUser, updateUser, or deleteUser here } // Initialize the model with your database schema User.init({ username: { type: DataTypes.STRING, allowNull: false }, email: { type: DataTypes.STRING, allowNull: false, unique: true } }, { sequelize, modelName: 'User' }); module.exports = User;
Step 2: User Controller (in /controllers/UserController.js)
The controller handles request/response flow and calls the model’s methods:
const User = require('../models/User'); class UserController { // Async/await version (cleaner for readability) static async getUsers(req, res) { try { // Wait for the Promise from the model to resolve const users = await User.getAllUsers(); res.status(200).json(users); } catch (error) { res.status(500).json({ error: error.message }); } } // .then() version (if you prefer chaining over async/await) // static getUsers(req, res) { // User.getAllUsers() // .then(users => res.status(200).json(users)) // .catch(error => res.status(500).json({ error: error.message })); // } } module.exports = UserController;
Step 3: Route Definition (in /routes/users.js)
Map HTTP endpoints to controller methods:
const express = require('express'); const router = express.Router(); const UserController = require('../controllers/UserController'); // GET all users router.get('/', UserController.getUsers); module.exports = router;
Step 4: Connect Routes to app.js
In your main entry file, mount the routes and start the server:
const express = require('express'); const app = express(); const userRoutes = require('./routes/users'); // Middleware to parse JSON requests app.use(express.json()); // Mount user routes at /api/users app.use('/api/users', userRoutes); // Start server const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); });
Fixing Your Original Promise Issue
Your earlier mistake was either not returning the Sequelize Promise from your class method, or trying to resolve an undefined Promise. By returning findAll() directly (which is already a Promise), you can use await or .then() to handle the result properly—no need to manually create a new Promise unless you’re adding custom logic before resolving.
Let’s turn this into a beginner-friendly walkthrough:
Prerequisites
- Node.js installed
- Basic knowledge of ES6 classes and Promises
- A database (PostgreSQL, MySQL, etc.) set up
Step 1: Initialize the Project
- Create a project folder and navigate into it:
mkdir node-oop-demo && cd node-oop-demo - Initialize npm:
npm init -y - Install dependencies:
npm install express sequelize pg pg-hstore # Use mysql2 instead of pg for MySQL npm install --save-dev nodemon # Auto-reloads server during development
Step 2: Set Up Sequelize
Create /config/database.js to configure your database connection:
const { Sequelize } = require('sequelize'); const sequelize = new Sequelize('your-db-name', 'your-db-username', 'your-db-password', { host: 'localhost', dialect: 'postgres' // or 'mysql' }); // Test the connection async function testConnection() { try { await sequelize.authenticate(); console.log('Database connection successful!'); } catch (error) { console.error('Connection failed:', error); } } testConnection(); module.exports = sequelize;
Step 3: Create Model Classes
Add your model files (like User.js) in /models as shown earlier.
Step 4: Build Controllers
Create controller classes in /controllers to handle request/response logic.
Step 5: Define Routes
Map endpoints to controller methods in /routes.
Step 6: Configure the Server
Set up Express in app.js, add middleware, and mount your routes.
Step 7: Run the Project
Add a script to package.json:
"scripts": { "start": "node app.js", "dev": "nodemon app.js" }
Start the dev server:
npm run dev
内容的提问来源于stack exchange,提问作者Maxime OBLE

