如何通过JavaScript Promise链循环向数组添加三个菜谱数据?
Hey there! Let's break down why your code isn't adding three recipes to the array as you expect, and fix it up.
The Problem
Right now, in your first .then() block, you're looping three times and calling getFood(data) each time—but these are asynchronous operations. JavaScript doesn't wait for them to finish before moving on to return(data). That means when the second .then() runs, only the first recipe has been added to the array; the other three requests are still in progress in the background.
On top of that, your code doesn't handle errors from the API request, which could leave your Promise stuck in a pending state if something goes wrong.
The Fix
We need to make sure we wait for all those asynchronous getFood calls to complete before moving on. Here are two clean ways to do this:
Option 1: Using Promise Chaining with reduce (pure Promise style)
This approach chains the three requests sequentially, so each one waits for the previous to finish before fetching the next recipe:
var request = require('request'); // Updated getFood with error handling and pure array updates getFood = function(lst){ return new Promise(function(resolve, reject){ request('https://api.jamesoff.net/recipe', function (error, response, recipe) { // Handle API errors first if (error) { return reject(error); } // Create a new array instead of modifying the input (avoids side effects) const updatedList = [...lst, JSON.parse(recipe)]; resolve(updatedList); }) }); } getFood([]) .then(function(initialData){ // Use reduce to chain 3 sequential getFood calls return [1,2,3].reduce((currentPromise) => { return currentPromise.then(updatedData => getFood(updatedData)); }, Promise.resolve(initialData)); }) .then(function(finalData){ console.log(finalData); // Now contains 4 recipes (initial + 3 looped) }) .catch(function(error){ // Don't forget to handle errors! console.error('Failed to fetch recipes:', error); });
Option 2: Using async/await (more readable)
If you're comfortable with modern JavaScript, async/await makes asynchronous code look synchronous, which is easier to follow:
var request = require('request'); const getFood = function(lst){ return new Promise(function(resolve, reject){ request('https://api.jamesoff.net/recipe', function (error, response, recipe) { if (error) { return reject(error); } resolve([...lst, JSON.parse(recipe)]); }) }); } // Async function to handle sequential fetching async function fetchThreeRecipes() { let recipes = []; // Loop 3 times, waiting for each request to finish before the next for (let i = 0; i < 3; i++) { recipes = await getFood(recipes); } console.log(recipes); // Contains exactly 3 recipes } // Run the function and catch any errors fetchThreeRecipes().catch(err => console.error('Error:', err));
Key Changes Explained
- Error Handling: We added checks for API request errors and reject the Promise when something goes wrong—this prevents hanging Promises and lets you debug issues easily.
- Waiting for Async Operations: Instead of firing off requests and immediately returning the array, we now wait for all three requests to complete before moving to the final
.then()(or logging in the async function). - Pure Array Updates: Creating a new array with
[...lst, newRecipe]instead of modifying the input array avoids unexpected side effects, making your code more predictable.
If you wanted only 3 total recipes (instead of 4), just replace the initial getFood([]) with Promise.resolve([]) in the first option, or keep the async function as-is—it starts with an empty array and adds three recipes.
内容的提问来源于stack exchange,提问作者hope1234

