JavaScript等待Tasker外部数据的循环实现问题求助
Tasker与WebView JS数据等待循环问题修复
问题背景
在Android设备的Tasker场景WebView中运行带JS的HTML页面,需要展示Google Places API结果。Tasker从Google拉取数据的流程正常,JS也能读取到数据,但构建等待Tasker完成检索的循环时出现两个问题:
- 检测到控制变量匹配后,对应代码块重复执行多次
this.fillHtmlElements()函数完全没执行- 固定时长的
setTimeout能运行,但无法适配网络波动情况
原尝试代码
loadContent(){ const myInterval = setInterval(dataRetrieve, 500); let random = Math.random().toFixed(5); // 生成随机数作为控制变量 setGlobal('CheckNumberIn', random); // 将控制变量设置到Tasker全局变量CheckNumberIn,Tasker完成加载后会把CheckNumberOut设为相同值 performTask('loadingGoogle', '15', this.locationType, Data.distance); // 启动Tasker任务loadingGoogle获取数据,15是优先级,this.locationType是地点类型,Data.distance是搜索半径 let counter = 0; function dataRetrieve() { let answer = global('CheckNumberOut'); // 获取Tasker全局变量CheckNumberOut的值 if (answer == random) { // 检查控制变量是否相等,判断Tasker是否完成加载 let retrievedData = global ('RetrievedData'); // 读取Tasker中存储的检索数据 this.inputData = JSON.parse(this.retrievedData); // 解析JSON数据 this.fillHtmlElements(); // 更新HTML元素 clearInterval(myInterval); } else if (counter < 30) { counter++; } else { clearInterval(myInterval); } } }
问题根源
this指向错误:dataRetrieve作为内部函数,在setInterval回调中执行时,this不再指向loadContent所属的对象,导致this.inputData和this.fillHtmlElements()无法正确访问,所以更新函数没执行。- 重复执行未阻止:当控制变量匹配后,虽然调用了
clearInterval,但已经进入执行队列的回调还会继续运行,导致代码块重复执行多次。
修复方案
修复后的代码
loadContent(){ let isCompleted = false; // 标记是否已处理完成,防止重复执行 const self = this; // 保存当前上下文的this引用 const myInterval = setInterval(dataRetrieve, 500); let random = Math.random().toFixed(5); setGlobal('CheckNumberIn', random); performTask('loadingGoogle', '15', this.locationType, Data.distance); let counter = 0; function dataRetrieve() { if (isCompleted) return; // 已完成则直接返回,避免重复处理 let answer = global('CheckNumberOut'); if (answer == random) { isCompleted = true; clearInterval(myInterval); // 先清除定时器,阻止后续回调 let retrievedData = global('RetrievedData'); self.inputData = JSON.parse(retrievedData); // 使用self访问原上下文的属性 self.fillHtmlElements(); // 执行HTML更新函数 } else if (counter < 30) { counter++; } else { clearInterval(myInterval); // 这里可以添加超时提示逻辑,比如给用户显示加载失败 } } }
简化版(箭头函数)
箭头函数会继承外层作用域的this,可以省去保存self的步骤:
loadContent(){ let isCompleted = false; let random = Math.random().toFixed(5); let counter = 0; setGlobal('CheckNumberIn', random); performTask('loadingGoogle', '15', this.locationType, Data.distance); const myInterval = setInterval(() => { if (isCompleted) return; let answer = global('CheckNumberOut'); if (answer == random) { isCompleted = true; clearInterval(myInterval); let retrievedData = global('RetrievedData'); this.inputData = JSON.parse(retrievedData); this.fillHtmlElements(); } else if (counter < 30) { counter++; } else { clearInterval(myInterval); } }, 500); }
进阶优化(Promise封装)
用Promise封装等待逻辑,让代码更清晰易读:
// 封装等待Tasker数据的函数 function waitForTaskerData(checkValue) { return new Promise((resolve, reject) => { let counter = 30; const interval = setInterval(() => { const answer = global('CheckNumberOut'); if (answer === checkValue) { clearInterval(interval); resolve(global('RetrievedData')); } else if (--counter <= 0) { clearInterval(interval); reject(new Error('数据加载超时')); } }, 500); }); } // 异步方式调用 async loadContent() { const random = Math.random().toFixed(5); setGlobal('CheckNumberIn', random); performTask('loadingGoogle', '15', this.locationType, Data.distance); try { const retrievedData = await waitForTaskerData(random); this.inputData = JSON.parse(retrievedData); this.fillHtmlElements(); } catch (error) { console.error(error); // 这里处理超时或加载失败的情况,比如给用户提示 } }
内容的提问来源于stack exchange,提问作者Philipp Mayer
相关产品推荐
相关产品推荐

