异步函数返回值问题:如何让XMLHttpRequest/fetch向父函数返回数据
异步请求返回undefined的问题解决及Fetch API用法
问题根源
你遇到的bookss输出undefined的核心原因是XMLHttpRequest是异步操作:
fetchBooks函数执行到xhr.send()后就直接结束了,默认返回undefined;onload回调里的return books是在请求完成后才触发的,这个返回值根本传不到homepage的bookss变量里。
修复XMLHttpRequest版本
用Promise包装异步操作,让fetchBooks返回一个Promise,再通过async/await或者.then()获取结果:
function fetchBooks() { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open("GET", "url"); xhr.onload = () => { if (xhr.status === 200) { const books = []; // 注意每次创建新的book对象,避免全局变量引用问题 const book = { name: book_name, id: book_id, genre: book_genre, language: book_language, date: book_date }; books.push(book); console.log(books); resolve(books); // 请求成功时传递结果 } else { reject(new Error(`请求错误: ${xhr.status}`)); } }; // 处理网络错误 xhr.onerror = () => reject(new Error("网络请求失败")); xhr.send(); }); } // 父函数用async/await调用 async function homepage() { // do stuff try { const bookss = await fetchBooks(); console.log(bookss); } catch (err) { console.error(err); } }
Fetch API实现方案
Fetch本身基于Promise,写法更简洁,解析HTML可以用DOMParser:
async function fetchBooks() { try { const response = await fetch("url"); // 检查请求是否成功 if (!response.ok) { throw new Error(`请求错误: ${response.status}`); } // 获取HTML文本内容 const htmlText = await response.text(); // 解析HTML为DOM对象 const parser = new DOMParser(); const doc = parser.parseFromString(htmlText, "text/html"); const books = []; // 示例:假设从class为book-item的元素中提取图书数据 const bookItems = doc.querySelectorAll(".book-item"); bookItems.forEach(item => { const book = { name: item.querySelector(".book-name").textContent.trim(), id: item.dataset.bookId, genre: item.querySelector(".book-genre").textContent.trim(), language: item.querySelector(".book-lang").textContent.trim(), date: item.querySelector(".book-date").textContent.trim() }; books.push(book); }); return books; } catch (err) { console.error(err); throw err; // 抛出错误让调用者处理 } } // 父函数调用方式 async function homepage() { // do stuff try { const bookss = await fetchBooks(); console.log(bookss); } catch (err) { console.error(err); } }
额外注意事项
- 原代码中
book变量未声明,会变成全局变量,导致所有push的都是同一个对象的引用,必须每次创建新的book对象; - 所有异步操作的结果都必须通过Promise链式调用或
async/await获取,不能直接同步赋值。
内容的提问来源于stack exchange,提问作者ducc
相关产品推荐
相关产品推荐

