JavaScript函数返回undefined:已定义变量且从IndexedDB取值仍异常
问题根源:IndexedDB是异步操作,你的函数同步返回了
你遇到的问题核心在于IndexedDB的所有操作都是异步的,而你的code1函数是同步执行的——函数在触发IndexedDB的请求后,还没等异步操作完成(也就是onsuccess回调执行),就已经执行完毕,自然返回undefined。
下面给你两种可行的解决方案,适配不同的代码风格:
方案1:用Promise封装(推荐,现代JS写法)
把整个检索逻辑封装成Promise,这样你可以用async/await或者.then()来优雅地获取异步结果:
function code1(sname) { return new Promise((resolve, reject) => { const request1 = indexedDB.open("footballDatabase", 1); request1.onsuccess = function(evt) { const db = evt.target.result; const objectStore = db.transaction("teamsData").objectStore("teamsData"); const cursorRequest = objectStore.openCursor(); cursorRequest.onsuccess = function(event) { const cursor = event.target.result; if (cursor) { if (cursor.value.name === sname) { // 匹配到目标数据,resolve返回结果 resolve(cursor.value); db.close(); // 记得关闭数据库连接 } else { // 没匹配到,继续遍历下一条 cursor.continue(); } } else { // 遍历完所有数据都没找到,resolve返回null resolve(null); db.close(); } }; cursorRequest.onerror = function(err) { reject(err); db.close(); }; }; request1.onerror = function(err) { reject(err); }; }); } // 调用方式(用async/await): async function getTargetTeam(sname) { try { const result = await code1(sname); if (result) { console.log("找到匹配数据:", result); // 这里处理你的业务逻辑 } else { console.log("没有找到对应名称的数据"); } } catch (err) { console.error("检索过程出错:", err); } } // 或者用.then()链式调用: code1("曼联") .then(result => { result ? console.log("找到数据:", result) : console.log("无匹配结果"); }) .catch(err => console.error(err));
方案2:使用回调函数(传统写法)
如果不想用Promise,也可以给code1添加一个回调参数,在异步操作完成后调用回调返回结果:
function code1(sname, callback) { const request1 = indexedDB.open("footballDatabase", 1); request1.onsuccess = function(evt) { const db = evt.target.result; const objectStore = db.transaction("teamsData").objectStore("teamsData"); const cursorRequest = objectStore.openCursor(); cursorRequest.onsuccess = function(event) { const cursor = event.target.result; if (cursor) { if (cursor.value.name === sname) { // 匹配到数据,调用回调返回结果 callback(null, cursor.value); db.close(); } else { cursor.continue(); } } else { // 遍历完毕无匹配,回调返回null callback(null, null); db.close(); } }; cursorRequest.onerror = function(err) { callback(err, null); db.close(); }; }; request1.onerror = function(err) { callback(err, null); }; } // 调用方式: code1("切尔西", function(err, result) { if (err) { console.error("检索出错:", err); return; } result ? console.log("找到数据:", result) : console.log("未找到匹配项"); });
额外性能优化建议
其实你不需要遍历整个游标来查找匹配项,IndexedDB支持索引(Index),如果name字段是常用查询条件,建议给teamsData对象仓库创建一个name索引,这样可以直接通过索引快速定位数据,避免全表扫描:
// 先确保在数据库升级时创建索引(首次打开数据库版本号更新时执行): // request1.onupgradeneeded = function(evt) { // const db = evt.target.result; // const objectStore = db.createObjectStore("teamsData", { keyPath: "id" }); // objectStore.createIndex("name", "name", { unique: false }); // 创建name字段的索引 // }; // 优化后的查询函数: function code1(sname) { return new Promise((resolve, reject) => { const request1 = indexedDB.open("footballDatabase", 1); request1.onsuccess = function(evt) { const db = evt.target.result; const objectStore = db.transaction("teamsData").objectStore("teamsData"); const nameIndex = objectStore.index("name"); const getRequest = nameIndex.get(sname); getRequest.onsuccess = function() { resolve(getRequest.result); db.close(); }; getRequest.onerror = function(err) { reject(err); db.close(); }; }; request1.onerror = function(err) { reject(err); }; }); }
这样查询效率会比遍历游标高很多,尤其是数据量较大的时候。
内容的提问来源于stack exchange,提问作者Sanjay S
相关产品推荐
相关产品推荐

