在循环内调用AsyncStorage.setItem导致应用崩溃如何解决?
问题现象
React Native开发中调用AsyncStorage存储数据时,应用无提示崩溃,仅函数入口的console.log("ran")可正常输出,循环内的日志完全没有打印,崩溃逻辑通过Pressable组件的onPress事件触发。
问题代码如下:
const saving = () => { console.log("ran") // 可正常执行 let loop = true let cont = 0 while (loop == true) { console.log("got here") // 完全没触发 AsyncStorage.getItem(`Item-${cont}`, (error, result) => { console.log("here") if (error) { Toast.show({ type: 'error', text1: 'An error has ocurred!' }) loop = false } else if (result == null) { AsyncStorage.setItem(`Item-${cont}`, (error) => { console.log("there") if (error) { Toast.show({ type: 'error', text1: 'Error occurred while saving workout!' }) loop = false } else { Toast.show({ type: 'success', text1: 'Workout saved successfully!' }) loop = false } }) } }) cont++ } }
<Pressable onPress={() => saving()} > </Pressable>
崩溃根因
- 核心问题是同步while死循环完全堵死JS单线程:JS运行时是单线程模型,AsyncStorage的读写回调属于异步任务,必须等当前所有同步代码执行完毕才会被调度执行。也就是说while循环启动后,回调里修改
loop = false的逻辑永远没有执行机会,cont变量会无限自增,瞬间占满内存导致应用直接崩溃,没有报错是因为崩溃速度太快,错误捕获、日志输出逻辑都没来得及触发。 - 看不到
console.log("got here")的打印不是代码没进入循环,是死循环占满了全部线程资源,console的日志还没来得及通过React Native的调试桥传输到控制台,程序就已经终止了。 - 代码存在显性参数错误:
AsyncStorage.setItem的标准调用签名是setItem(键名, 待存储的字符串值, 回调函数),当前代码只传了键名和回调,缺少必填的存储值参数,就算循环不卡死,走到这行也会抛出异常。
修复方案
不要用同步循环等待异步回调,直接用async/await改写逻辑,按顺序查找空的存储位,找到后写入数据再退出循环即可:
import AsyncStorage from '@react-native-async-storage/async-storage'; const saving = async () => { console.log("ran") let cont = 0 while (true) { const storageKey = `Item-${cont}` try { const existResult = await AsyncStorage.getItem(storageKey) if (existResult === null) { // 下方第二个参数替换为你实际要存储的内容,注意AsyncStorage仅支持字符串类型,对象需要提前JSON.stringify序列化 await AsyncStorage.setItem(storageKey, JSON.stringify({ // 替换为实际要存的训练数据 })) Toast.show({ type: 'success', text1: '训练保存成功!' }) break } cont++ } catch (err) { Toast.show({ type: 'error', text1: '保存失败,请重试!' }) break } } }
Pressable的绑定逻辑无需额外修改,也可以简写成onPress={saving}。
- 优化提示:如果后续存储的条目越来越多,每次从0开始遍历找空key会越来越慢,可以单独维护一个
ItemTotalCount的存储键,每次保存时直接读取这个计数值拼接key,存完数据后把计数值+1写回存储,省去遍历的开销。
内容的提问来源于stack exchange,提问作者hrodric
相关产品推荐
相关产品推荐

