开发日常疑问——怎么中断执行中的函数?

265 阅读2分钟

需求描述

搜索功能——连续输入多次请求执行最后一次

常规方案

通过延迟执行——函数防抖 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里的使用注意事项

  1. 在src下新建workers/index.js文件——注意是js文件
  2. app.config.ts里配置
export default {
  workers: 'workers',
};
  1. 在config/index.js里配置
const config = {
  copy: {
    patterns: [{ from: 'src/workers', to: 'dist/workers' }],
    options: {},
  },
};

总结

这样的方式实现了最初的目的,但是呢我觉得有点可以但没有必要的感觉,代价大了点。哈哈哈,又是摸鱼的一篇文章。