需求描述
搜索功能——连续输入多次请求执行最后一次
常规方案
通过延迟执行——函数防抖 setTimeout(() => {}, 300)
遐想
- 是否可以直接下次请求执行的时候中断上次请求?无需延迟
- 连续输入结果超过时间间隔,第一次请求结果返回晚于第二次请求会照成干扰。
探究
通过资料查阅(百度一下)发现没有这种解决方案。原因就是JS是单线程的所以没办法在后续的函数中终止前面函数的内容。解释一下:小老弟排到队伍执行终止前面代码的时候,前面代码已经执行完了。也就是著名的格林公式"在你来之前,我们已经是冠军了"。 那么全文水完了吗?
不好意思,我们是开发小程序,小程序是有多线程的。所以try try 看啊。
方案确定:小程序多线程
代码示例
主线程代码
import { Input, View } from '@tarojs/components';
import Taro from '@tarojs/taro';
import React, { useRef } from 'react';
import styles from './index.module.less';
const Index: React.FC = () => {
const workerRef = useRef<any>(null);
// 创建线程
const createWorker = () => {
workerRef.current?.terminate();
workerRef.current = Taro.createWorker('workers/index.js');
};
/**
* 主线程搜索方法——创建线程并通知搜索
* @param searchKey
*/
const search = (searchKey) => {
createWorker();
workerRef.current.postMessage({ searchKey });
workerRef.current.onMessage((resp) => {
console.log('resp', resp);
});
};
return (
<View className={styles.container}>
<Input
placeholder={'请输入'}
onInput={(e) => {
search(e.detail.value);
}}
/>
</View>
);
};
export default Index;
新建线程代码
// 监听搜索
worker.onMessage((params) => {
loadPageSearchApi(params).then((resp) => {
// 通知搜索结果
worker.postMessage(resp);
});
});
// 搜索函数模拟
const loadPageSearchApi = async ({ searchKey }) => {
const resp = await new Promise((resolve) => {
setTimeout(() => {
const dataSource = [];
for (let i = 0; i < 30; i++) {
const id = i + 1;
dataSource.push({ id, name: `id: ${id}` });
}
const searchList = dataSource.filter((item) =>
item.name.includes(searchKey),
);
resolve({
data: {
list: searchList,
total: searchList.length,
},
});
}, 1000);
});
return resp || {};
};
worker在taro里的使用注意事项
- 在src下新建workers/index.js文件——注意是js文件
- app.config.ts里配置
export default {
workers: 'workers',
};
- 在config/index.js里配置
const config = {
copy: {
patterns: [{ from: 'src/workers', to: 'dist/workers' }],
options: {},
},
};
总结
这样的方式实现了最初的目的,但是呢我觉得有点可以但没有必要的感觉,代价大了点。哈哈哈,又是摸鱼的一篇文章。