You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Node+Express中用Promise处理API请求并解决EJS展示的异步问题

Got it, let's work through this problem together. I totally get the frustration when async requests leave you with partial data—especially when you need all those NASA APOD images to load properly before rendering the page. Let's fix this using Promises in Node/Express and get your EJS page showing all the data correctly.

Step 1: Install Required Dependencies

First, make sure you have tools to handle API requests and template rendering. We'll use axios for HTTP calls, express for the server, and ejs for templating:

npm install axios express ejs
Step 2: Backend Route with Promise.all to Sync Async Requests

The core issue here is that your previous code was probably rendering the page before all API requests finished. Using Promise.all lets us wait for both the APOD and Launch Library data to be fully fetched before passing it to the EJS template.

Here's how to set up your route (e.g., in routes/space.js or directly in app.js):

const express = require('express');
const router = express.Router();
const axios = require('axios');

// Configure API details
const NASA_API_KEY = 'your-nasa-api-key-here'; // Get this from NASA's developer portal
const APOD_API_URL = `https://api.nasa.gov/planetary/apod?api_key=${NASA_API_KEY}&count=10`;
const LAUNCH_LIBRARY_URL = 'https://ll.thespacedevs.com/1.3/launch/upcoming?limit=5';

// Fetch APOD images (returns a Promise)
const fetchAPODImages = async () => {
  try {
    const res = await axios.get(APOD_API_URL);
    // Filter out videos—only keep images since you want to display them
    return res.data.filter(item => item.media_type === 'image');
  } catch (err) {
    console.error('Failed to fetch APOD data:', err);
    return []; // Return empty array to prevent page crashes
  }
};

// Fetch upcoming launches (returns a Promise)
const fetchUpcomingLaunches = async () => {
  try {
    const res = await axios.get(LAUNCH_LIBRARY_URL);
    return res.data.results;
  } catch (err) {
    console.error('Failed to fetch launch data:', err);
    return [];
  }
};

// Route to render the space page
router.get('/space', async (req, res) => {
  try {
    // Wait for both API requests to complete before proceeding
    const [apodImages, upcomingLaunches] = await Promise.all([
      fetchAPODImages(),
      fetchUpcomingLaunches()
    ]);

    // Pass full datasets to EJS template
    res.render('space', { apodImages, upcomingLaunches });
  } catch (err) {
    console.error('Error rendering space page:', err);
    res.status(500).send('Something went wrong on the server');
  }
});

module.exports = router;
Step 3: EJS Template to Display All Data

Create a views/space.ejs file to render the fetched data. Since we're passing fully loaded datasets, all images and launch info will be ready to display:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Space Dashboard</title>
  <style>
    .apod-grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
      gap: 20px;
      margin: 2rem 0;
    }
    .apod-card {
      border: 1px solid #eee;
      border-radius: 8px;
      padding: 1rem;
      box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    }
    .apod-card img {
      width: 100%;
      height: 220px;
      object-fit: cover;
      border-radius: 4px;
      margin-bottom: 1rem;
    }
    .launch-item {
      margin: 1.5rem 0;
      padding: 1rem;
      border-left: 4px solid #2563eb;
      background-color: #f8fafc;
      border-radius: 0 4px 4px 0;
    }
  </style>
</head>
<body>
  <h1>NASA APOD: Recent 10 Images</h1>
  <div class="apod-grid">
    <% if (apodImages.length) { %>
      <% apodImages.forEach(image => { %>
        <div class="apod-card">
          <img src="<%= image.url %>" alt="<%= image.title %>">
          <h3><%= image.title %></h3>
          <p><%= image.date %></p>
        </div>
      <% }) %>
    <% } else { %>
      <p>Failed to load APOD images. Please try again later.</p>
    <% } %>
  </div>

  <h1>Upcoming Space Launches</h1>
  <div class="launch-list">
    <% if (upcomingLaunches.length) { %>
      <% upcomingLaunches.forEach(launch => { %>
        <div class="launch-item">
          <h3><%= launch.name %></h3>
          <p><strong>Launch Time:</strong> <%= new Date(launch.net).toLocaleString() %></p>
          <p><strong>Rocket:</strong> <%= launch.rocket.name %></p>
          <p><strong>Location:</strong> <%= launch.pad.location.name %></p>
        </div>
      <% }) %>
    <% } else { %>
      <p>Failed to load launch information. Please try again later.</p>
    <% } %>
  </div>
</body>
</html>
Key Fix Explanation

The main reason some APOD images weren't loading before is that your code was likely rendering the page before all APOD requests finished. Promise.all waits for every Promise passed to it to resolve, so we only send data to the EJS template once both datasets are fully ready. No more partial loads!

We also added a filter for APOD images to skip video entries (since those won't render as images in your grid) and added error handling to prevent the server from crashing if an API request fails.

内容的提问来源于stack exchange,提问作者Christopher Berry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 04:20:56