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

React Native中SQLite异步存储Blob/Base64图片并读取显示问题

解决方案:SQLite异步插入Blob图片问题

问题根源

  1. 原代码中result.map(async item => ...)生成的异步函数未被等待,事务可能在convertImageToBase64返回结果前提前结束,导致插入空值。
  2. tx.executeSql是回调式异步操作,未包装为Promise时无法用await控制执行顺序,造成事务内操作混乱。
  3. 若需存储Blob类型,直接存入Base64字符串不符合需求,需转换为Blob对象。

方案一:顺序异步处理(适合需要保证插入顺序的场景)

db.transaction(async (tx) => {
  // 用for...of循环替代map,确保每个异步操作完成后再执行下一个
  for (const item of result) {
    try {
      // 等待Base64转换完成
      const base64Data = await convertImageToBase64(item.imgUrl);
      // 将Base64转换为Blob对象
      const imgBlob = base64ToBlob(base64Data);
      // 将tx.executeSql包装为Promise,确保插入完成后再继续
      await new Promise((resolve, reject) => {
        tx.executeSql(
          "INSERT INTO markets (name, imgUrl, done) VALUES (?,?,?)",
          [item.name, imgBlob, item.done],
          (tx, results) => {
            console.log("插入成功,影响行数:", results.rowsAffected);
            resolve();
          },
          (error) => {
            console.error("插入失败:", error);
            reject(error);
          }
        );
      });
    } catch (err) {
      console.error("处理数据失败:", err);
      throw err; // 抛出错误触发事务回滚
    }
  }
});

// Base64转Blob辅助函数
function base64ToBlob(base64) {
  const parts = base64.split(';base64,');
  const contentType = parts[0].split(':')[1];
  const rawData = window.atob(parts[1]);
  const uint8Array = new Uint8Array(rawData.length);
  
  for (let i = 0; i < rawData.length; i++) {
    uint8Array[i] = rawData.charCodeAt(i);
  }
  
  return new Blob([uint8Array], { type: contentType });
}

方案二:批量预处理+插入(适合性能优先、无需严格顺序的场景)

先批量完成所有图片的Base64转Blob操作,再统一执行事务插入:

// 第一步:批量处理所有图片数据
const processedItems = await Promise.all(
  result.map(async (item) => {
    const base64Data = await convertImageToBase64(item.imgUrl);
    const imgBlob = base64ToBlob(base64Data);
    return { ...item, imgBlob };
  })
);

// 第二步:在事务中批量插入
db.transaction(async (tx) => {
  for (const item of processedItems) {
    await new Promise((resolve, reject) => {
      tx.executeSql(
        "INSERT INTO markets (name, imgUrl, done) VALUES (?,?,?)",
        [item.name, item.imgBlob, item.done],
        (tx, results) => {
          console.log("插入成功,影响行数:", results.rowsAffected);
          resolve();
        },
        (error) => {
          console.error("插入失败:", error);
          reject(error);
        }
      );
    });
  }
});

// 复用Base64转Blob辅助函数
function base64ToBlob(base64) {
  const parts = base64.split(';base64,');
  const contentType = parts[0].split(':')[1];
  const rawData = window.atob(parts[1]);
  const uint8Array = new Uint8Array(rawData.length);
  
  for (let i = 0; i < rawData.length; i++) {
    uint8Array[i] = rawData.charCodeAt(i);
  }
  
  return new Blob([uint8Array], { type: contentType });
}

额外说明

  • 若你的SQLite封装(如某些WebSQL兼容库)不直接支持Blob参数,可将Blob转换为ArrayBuffer后插入,部分库会自动识别并存储为Blob类型。
  • 读取图片时,从数据库取出Blob对象后,可通过URL.createObjectURL(blob)生成可用于<img>标签的URL。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 18:15:36