IndexedDB存储对象时报错”Failed to execute ‘put’ on ‘IDBObjectStore’,该怎么解决?

小焕焕 阅读 17

在开发待办事项应用时,我尝试用IndexedDB存储包含日期的Task对象,但执行put操作就报错:

Uncaught DOMException: Failed to execute 'put' on 'IDBObjectStore': The object's keys are not all scalar values.
    at addTask (todo.js:23:18)

我的数据结构是这样的:

const task = {
  id: 1,
  title: '测试任务',
  dueDate: new Date() // 这里用了Date对象
}

已经按照文档创建了对象存储:

const store = db.createObjectStore('tasks', { keyPath: 'id' });
store.createIndex('dueDate', 'dueDate', { unique: false });

尝试过把dueDate转成字符串,但不确定是不是最好的解决办法,有没有更规范的处理方式?

我来解答 赞 2 收藏
二维码
手机扫码查看
1 条解答
UP主~羽沫
这个问题我之前也碰到过,确实是IndexedDB的一个小坑。报错的核心原因是因为IndexedDB要求存储的对象属性必须是可序列化的标量值,而你直接用了Date对象,它不是标量值类型。

最规范的解决方法是把Date对象转成时间戳存储,因为时间戳是number类型,完全符合IndexedDB的要求。取数据的时候再转回Date对象,这样既规范又不会丢失精度。

给你一个完整的处理示例:


// 存储时
const task = {
id: 1,
title: '测试任务',
dueDate: new Date().getTime() // 转成时间戳
};

store.put(task);

// 取出时
const handleTask = (task) => {
task.dueDate = new Date(task.dueDate); // 转回Date对象
console.log(task);
};


另外提醒一下,记得修改索引的定义方式,因为存储格式变了:


store.createIndex('dueDate', 'dueDate', { unique: false });


这样做还有一个好处就是时间戳在查询和排序时性能会更好。我之前试过存ISO字符串,但处理起来还是没有时间戳方便。

对了,如果你用的是现代浏览器,也可以考虑用structuredClone来深拷贝对象,不过在这个场景下时间戳的方式更简单直接。
点赞 2
2026-02-16 22:03