sqlite React原生JS同步

rdlzhqv9  于 2022-11-14  发布在  SQLite
关注(0)|答案(2)|浏览(177)

我正在写一个歌词应用程序,保存一本歌曲书和那本书中的歌曲到一个SQL lite数据库。我正在Map一组书籍,并调用一个API来保存书籍的歌曲。在转到saveBookSong()函数之前,我希望saveBook()函数完全完成。我已经尝试了异步等待,但它不起作用。任何帮助都将不胜感激,谢谢你,山姆

useEffect( () => {
   Books.map ((book) =>{
    saveBook(book)
    saveBookSong(book.songId.toString())
  })
function saveBook(book) {
   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)
        }
    );
  });
}
function saveBookSong(id) {
   axios
    .get(`songs/${id}`)
    .then((bookSong) => {
      bookSong.data.forEach((song) => {
        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,
            ],
            () => {
            }
          );
        });

      });
    })
    .catch((err) => {
      console.log(err);
    });
}
iszxjhcz

iszxjhcz1#

我假设您希望所有的书都并行保存。我会这么做:

useEffect( () => {
    const bookSavings = Books.map(async (book) =>{
        await saveBook(book)
        await saveBookSong(book.songId.toString())
    });
    // If you want to wait for all books to be saved
    await Promise.all(bookSavings);
    // ... Whatever else you want to do in your useEffect
}, [Books])

好的,但是您不能简单地使用awaitsaveBooksaveBookSong,因为它们不是async函数。让我们继续前进吧。
在幕后,异步函数只是返回承诺的函数。我们实际上可以await任何承诺。因此,您可以通过将saveBooksaveBookSong Package 在承诺中使它们成为可等待的,如下所示:

function saveBook(book) {
    return new Promise((resolve) => {
        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(); // <- THIS IS IMPORTANT
                }
            );
        });
    });
}

**EDIT:**第二个函数需要特别注意,因为正如您所指出的,它包含一个循环。然而,这与您拥有的顶级.map函数并没有什么不同。这是我的(未经检验的)建议,希望你能从这里开始工作。我将函数一分为二,以使其更易于理解:

async function saveBookSong(id) {
    const bookSong = await axios.get(`songs/${id}`);
    const savePromises = bookSong.data.map(song => {
        return saveSong(song);
    });
    await Promise.all(savePromises);
}

function saveSong(song) {
    return new Promise((resolve) => {
        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,
                ],
                resolve
            );
        }
    }
}
v440hwme

v440hwme2#

如果我没有记错的话,.map()不支持异步。因此,对于您的问题,我会提出两个解决方案:
1)

useEffect( () => {
   Books.map ((book) =>{
    saveBook(book).then(() => saveBookSong(book.songId.toString()))
  }, [Books])

在这种情况下,您可以在执行第一个函数后继续。
2)

useEffect( () => {
const manageBooks = async() => {
 for (book of Books) {
       await saveBook(book);
       await saveBookSong(book.songId.toString());
 }
}
      }, [Books])

您可以使用Async for循环,它将等待执行第一个任务,然后再移动到另一个任务

相关问题