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

使用Axios嵌套API调用返回Promise对象而非实际数据求助

图书目录系统异步请求问题排查

问题背景

我正在开发一个包含四个目录的图书目录系统:

  • All Directory
  • Ongoing Directory
  • Favorite Directory
  • Completed Directory

需求是:图书对应的按钮,当图书处于Ongoing Directory时显示"Ongoing",未处于该目录时显示"Start Reading"。目前在获取全部图书的API调用内,对每本图书发起查询其是否在Ongoing Directory的API调用,但嵌套调用返回的是[promise object]而非实际数据,导致页面显示异常。

原代码

const books_div = document.querySelector('.root');


const showAllBooks = async () => {
    console.log('running');

    try {

        const { data: { books } } = await axios.get('api/v1/home/all');
        console.log(books);
        if (books.length < 1) {
            books_div.innerHTML = '<h5 class="empty-list">No Books in your Directory</h5>'
            return
        }
        const allBooks = books.map(async (book) => {
            const { name, authorName, _id: bookID } = book;

            var readingStatus = 'Start Reading';
            try {
                const { data: { books: ongoingBooks } } = await axios.get(`api/v1/home/ongoing/${name}`);
                if (ongoingBooks.length !== 0) {
                    readingStatus = 'Ongoing';
                }
            } catch (error) {
                console.log(error);
            }

            return (
                `<div class="single-book">
                <div class="name-author-div">
                <h4>${name}</h4>
            <p class="author-name">${authorName}</p>
            </div>
            
            <div class="icon-div">
            <a class="favourite-btn" data-id="${bookID}"><img src="./icons/fav.svg" alt="star-icon"></a>
            <a class="delete-btn" data-id="${bookID}"><img src="./icons/dlt.svg" alt="bin-icon"></a>
            </div>
    
            <button class="btn">${readingStatus}</button>
            </div>`
            );
        }).join('');

        books_div.innerHTML = allBooks;
        console.log(`here is the book div ${books_div}`);

    } catch (error) {
        console.log(error);
    }
}



showAllBooks();

问题原因

books.map(async (book) => { ... })中,async函数的返回值是Promise对象,所以map遍历后得到的是一个Promise数组,而非HTML字符串数组。直接调用.join('')会把每个Promise对象转为字符串[object Promise],最终页面渲染的就是这些无效字符串。

解决方案

方案1:等待所有异步请求完成

使用Promise.all()等待map中所有Promise执行完毕,得到实际的HTML字符串数组后再拼接:

const books_div = document.querySelector('.root');

const showAllBooks = async () => {
    console.log('running');

    try {
        const { data: { books } } = await axios.get('api/v1/home/all');
        console.log(books);
        if (books.length < 1) {
            books_div.innerHTML = '<h5 class="empty-list">No Books in your Directory</h5>'
            return
        }

        // 生成每个图书对应的异步请求Promise
        const bookHtmlPromises = books.map(async (book) => {
            const { name, authorName, _id: bookID } = book;
            let readingStatus = 'Start Reading';
            try {
                const { data: { books: ongoingBooks } } = await axios.get(`api/v1/home/ongoing/${name}`);
                if (ongoingBooks.length !== 0) {
                    readingStatus = 'Ongoing';
                }
            } catch (error) {
                console.log(error);
            }

            return `
                <div class="single-book">
                    <div class="name-author-div">
                        <h4>${name}</h4>
                        <p class="author-name">${authorName}</p>
                    </div>
                    
                    <div class="icon-div">
                        <a class="favourite-btn" data-id="${bookID}"><img src="./icons/fav.svg" alt="star-icon"></a>
                        <a class="delete-btn" data-id="${bookID}"><img src="./icons/dlt.svg" alt="bin-icon"></a>
                    </div>
    
                    <button class="btn">${readingStatus}</button>
                </div>
            `;
        });

        // 等待所有Promise完成,获取HTML字符串数组
        const allBooksHtml = await Promise.all(bookHtmlPromises);
        books_div.innerHTML = allBooksHtml.join('');
        console.log(`here is the book div ${books_div}`);

    } catch (error) {
        console.log(error);
    }
}

showAllBooks();

方案2:优化API请求次数(推荐)

当前每本图书发起一次查询请求,属于N+1请求问题,性能较差。如果后端支持,建议先获取所有Ongoing目录的图书列表,再在前端匹配,只需两次API请求:

const books_div = document.querySelector('.root');

const showAllBooks = async () => {
    console.log('running');

    try {
        // 并行请求全部图书和Ongoing目录图书,提升效率
        const [allBooksResp, ongoingBooksResp] = await Promise.all([
            axios.get('api/v1/home/all'),
            axios.get('api/v1/home/ongoing') // 假设该接口返回所有Ongoing状态的图书
        ]);

        const { data: { books } } = allBooksResp;
        const { data: { books: ongoingBooks } } = ongoingBooksResp;
        // 将Ongoing图书的名称存入Set,快速判断图书状态
        const ongoingBookNames = new Set(ongoingBooks.map(item => item.name));

        if (books.length < 1) {
            books_div.innerHTML = '<h5 class="empty-list">No Books in your Directory</h5>'
            return
        }

        // 直接前端匹配状态,无需嵌套异步请求
        const allBooksHtml = books.map(book => {
            const { name, authorName, _id: bookID } = book;
            const readingStatus = ongoingBookNames.has(name) ? 'Ongoing' : 'Start Reading';

            return `
                <div class="single-book">
                    <div class="name-author-div">
                        <h4>${name}</h4>
                        <p class="author-name">${authorName}</p>
                    </div>
                    
                    <div class="icon-div">
                        <a class="favourite-btn" data-id="${bookID}"><img src="./icons/fav.svg" alt="star-icon"></a>
                        <a class="delete-btn" data-id="${bookID}"><img src="./icons/dlt.svg" alt="bin-icon"></a>
                    </div>
    
                    <button class="btn">${readingStatus}</button>
                </div>
            `;
        }).join('');

        books_div.innerHTML = allBooksHtml;
        console.log(`here is the book div ${books_div}`);

    } catch (error) {
        console.log(error);
    }
}

showAllBooks();

内容的提问来源于stack exchange,提问作者Prince Kumar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 08:50:27