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

React Native实现saveBook完成后再执行saveBookSong的问题求助

解决SQLite保存歌本后再保存对应歌曲的异步执行问题

你的代码核心问题在于saveBook和saveBookSong都是异步操作,但没有返回Promise,导致async/await无法生效。要实现"歌本保存完成后再执行歌曲保存"的逻辑,需要将两个函数改造为返回Promise的异步函数,再通过async/await严格控制执行顺序。

1. 改造saveBook为返回Promise的函数

将SQLite的回调式异步操作封装成Promise,确保歌本写入数据库完成后才触发后续逻辑:

function saveBook(book) {
  return new Promise((resolve, reject) => {
    db.transaction((tx) => {
      tx.executeSql(
        `INSERT INTO books (id, description, img, name, song_id)
         VALUES (?, ?, ?, ?, ?)`,
        [book.id, book.description, book.img, book.name, book.songId],
        () => {
          console.log("Saved!!", book.id);
          resolve(); // 保存成功后标记Promise完成
        },
        (tx, error) => {
          console.error("歌本保存失败:", book.id, error);
          reject(error); // 保存失败时抛出错误
        }
      );
    }, (error) => {
      console.error("歌本事务执行失败:", error);
      reject(error);
    });
  });
}

2. 改造saveBookSong为返回Promise的函数

不仅要等待API请求完成,还要确保当前歌本的所有歌曲都写入数据库后才完成Promise:

function saveBookSong(id) {
  return new Promise((resolve, reject) => {
    axios
      .get(`songs/${id}`)
      .then((bookSong) => {
        // 将每个歌曲的保存操作转为Promise
        const songSavePromises = bookSong.data.map(song => {
          return new Promise((songResolve, songReject) => {
            db.transaction((tx) => {
              tx.executeSql(
                `INSERT INTO songs (id, book, book_id, data, int_song_number, lang, search_title, song_number, title, url) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
                [
                  song.id,
                  song.book,
                  song.bookId,
                  song.data,
                  song.intSongNumber,
                  song.lang,
                  song.searchTitle,
                  song.songNumber,
                  song.title,
                  song.url,
                ],
                () => songResolve(),
                (tx, error) => {
                  console.error("歌曲保存失败:", song.id, error);
                  songReject(error);
                }
              );
            }, (error) => {
              console.error("歌曲事务执行失败:", error);
              songReject(error);
            });
          });
        });

        // 等待当前歌本的所有歌曲保存完成
        Promise.all(songSavePromises)
          .then(() => resolve())
          .catch(err => reject(err));
      })
      .catch((err) => {
        console.error("获取歌曲列表失败:", err);
        reject(err);
      });
  });
}

3. 在useEffect中用async/await控制执行顺序

注意不要直接在useEffect回调中写async,而是内部定义异步函数并调用;用for...of遍历歌本数组,确保每个歌本的保存与歌曲保存是串行执行的:

useEffect(() => {
  const saveAllData = async () => {
    for (const book of Books) {
      try {
        await saveBook(book); // 等待当前歌本保存完成
        await saveBookSong(book.songId.toString()); // 再执行对应歌曲的保存
      } catch (error) {
        console.error("歌本处理失败:", book.id, error);
        // 若需要遇到错误就中断所有操作,取消下面的注释
        // throw error;
      }
    }
  };

  saveAllData();
}, [Books]); // 依赖数组加入Books,确保数组更新时重新执行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 16:05:59