如何终止画图

  1. 设置一个flag标志位,点击按钮的时候改变标志位为true,在三个await中添加判断,如果标志位为true,则根据layerName清楚路径的layer,然后return函数,终止后面的await函数逻辑。

终止异步函数执行并撤销 UI 更新的方法

在 JavaScript 中,异步函数(如 createHistoryWays)的终止不是内置的(不像线程的 kill),因为 Promise 一旦启动就无法直接 "中断" 执行链。但可以通过 AbortController (现代浏览器/Node.js 支持,推荐)、状态标志事件驱动 机制来实现近似取消。终止的核心是:

  • 中断内部异步操作 :如 gisManager.getGis().routePlan(routes)(假设它是基于 fetch 或类似可取消的 Promise;如果不是,需要修改其实现以支持取消)。
  • 停止后续函数:在调用后续函数前检查取消信号。
  • 撤销 UI 更新:假设这些函数会更新 UI(e.g., 地图库如 Leaflet、Google Maps 或 ArcGIS 绘制路线/图标),需要在取消时调用清除方法(如移除 polyline 图层、图标标记)。

以下分析在执行 createHistoryWays(multiHistoryWayPoints) 的 20s 内(总 ~30s)触发终止的各种方法。我假设:

  • gisManager.getGis().routePlan 是异步的(返回 Promise),并可通过 AbortSignal 取消(如果不是,需要先修改其内部实现,例如包装在 fetch 中)。
  • UI 更新发生在 routePlan.then 回调中(e.g., 绘制地图元素),因此需要跟踪这些元素以便清除。
  • 终止触发:通过外部事件(如用户点击 "取消" 按钮)、定时器(setTimeout 20s 后触发)或状态变化。
  • 整体上下文:在 initFmeWayPoints.then 回调中修改调用方式,使用 async/await 以便控制。
1. 推荐方法:使用 AbortController(支持取消 Promise 和信号传播)

AbortController 是 Web API 标准(Node.js 15+ 支持),允许创建 AbortSignal,并在函数中检查/传播它。适用于取消 fetchXMLHttpRequest 或自定义 Promise。

步骤

  • 创建 AbortController。
  • 将其 signal 传递给每个函数(修改 createHistoryWayscreateWaytoTarget 以接受 signal 参数,并在 routePlan 中使用)。
  • 在 20s 内触发 abortController.abort()(e.g., 通过按钮或定时器)。
  • 在 abort 时,调用 UI 清除函数(e.g., clearHistoryRoutes()clearPeopleIcons()clearTargetRoutes())。
  • 后续函数:在 await 前检查 signal.aborted,如果已取消,则跳过。

代码修改示例

javascript 复制代码
// 全局或模块级 UI 清除函数(假设地图库有方法移除元素)
let historyRouteLayers = [];  // 跟踪历史路线图层
let peopleIconMarkers = [];   // 跟踪人员图标
let targetRouteLayers = [];   // 跟踪目标路线图层

function clearHistoryRoutes() {
  historyRouteLayers.forEach(layer => gisManager.getGis().removeLayer(layer));  // 示例:移除地图图层
  historyRouteLayers = [];
}
function clearPeopleIcons() {
  peopleIconMarkers.forEach(marker => gisManager.getGis().removeMarker(marker));
  peopleIconMarkers = [];
}
function clearTargetRoutes() {
  targetRouteLayers.forEach(layer => gisManager.getGis().removeLayer(layer));
  targetRouteLayers = [];
}

// 修改 createHistoryWays 以支持取消和 UI 跟踪
async function createHistoryWays(routes, signal = null) {
  if (!Array.isArray(routes) || routes.length === 0) return;
  try {
    // 假设 routePlan 支持 signal(如果基于 fetch: fetch(url, { signal }))
    const result = await gisManager.getGis().routePlan(routes, signal);  // 传递 signal
    // UI 更新:在 .then 中(但由于 await,这里是同步)
    historyRouteLayers.push(result.routeLayer);  // 假设 routePlan 返回图层对象
  } catch (err) {
    if (signal && err.name === 'AbortError') {
      console.log('createHistoryWays aborted');
      clearHistoryRoutes();  // 立即撤销 UI
      return;  // 退出
    }
    throw err;  // 其他错误向上抛
  }
}

// 类似修改 createWaytoTarget
async function createWaytoTarget(routes, signal = null) {
  // ... 类似逻辑,跟踪 targetRouteLayers,并在 catch 中 clearTargetRoutes()
}

// createFmePeoplelcon 假设同步,但如果异步,也支持 signal
function createFmePeoplelcon(locations, signal = null) {
  if (signal?.aborted) return;  // 检查已取消
  // UI 更新:添加图标
  locations.forEach(loc => {
    const marker = gisManager.getGis().addMarker(loc);  // 示例
    peopleIconMarkers.push(marker);
  });
}

// 在 initFmeWayPoints 的 .then 中使用
.then(async (res) => {
  // ... 数据处理逻辑 ...

  const abortController = new AbortController();  // 创建控制器
  const { signal } = abortController;

  // 外部触发终止:e.g., 20s 定时器,或按钮事件
  const timeoutId = setTimeout(() => {
    abortController.abort();  // 触发取消
    clearAllUI();  // 全局清除(可选)
  }, 20000);  // 20s 后取消

  // 或者通过事件:document.getElementById('cancelBtn').addEventListener('click', () => abortController.abort());

  try {
    await createHistoryWays(multiHistoryWayPoints, signal);  // 启动,传递 signal
    // 在 20s 内如果 aborted,这里会抛 AbortError 并 catch 中清除
    
    if (signal.aborted) {
      console.log('Operation cancelled after history ways');
      return;  // 停止后续
    }
    
    createFmePeoplelcon(fmePeopleLocation, signal);  // 检查 aborted
    
    if (signal.aborted) return;
    
    await createWaytoTarget(multiCurToTargetWays, signal);
  } catch (err) {
    if (err.name === 'AbortError') {
      console.log('Overall operation aborted');
      // 撤销所有 UI
      clearHistoryRoutes();
      clearPeopleIcons();
      clearTargetRoutes();
    } else {
      // 处理其他错误
      throw err;
    }
  } finally {
    clearTimeout(timeoutId);  // 清理定时器
  }
});

// 全局清除函数
function clearAllUI() {
  clearHistoryRoutes();
  clearPeopleIcons();
  clearTargetRoutes();
}

执行时机和影响

  • 终止时机 :在 20s 内 abort() 触发时,routePlan 的 Promise 会 reject 以 AbortErrorcreateHistoryWays catch 它并清除 UI。随后检查 signal.aborted 阻止后续函数启动。
  • UI 撤销 :在 catch 或专用清除函数中立即调用,确保部分绘制的路线/图标被移除(e.g., 如果 routePlan 在 15s 开始绘制,20s 时移除)。
  • 优点:优雅、标准;信号可传播到嵌套 Promise;不阻塞其他代码。
  • 缺点 :需要修改 routePlan 支持 signal(e.g., 如果是第三方 API,包装它:new Promise((resolve, reject) => { /* 调用 API */ signal.addEventListener('abort', () => reject(new AbortError())) }))。如果 routePlan 不可取消,abort 只会停止等待,但后台可能继续(需检查其实现)。
  • 浏览器兼容:IE 不支持,需 polyfill。
  • 总时间:如果取消,~20s 内完成清理;否则正常 ~30s+。
2. 简单方法:使用状态标志(布尔变量或 Promise)

如果 AbortController 不可用或 routePlan 难修改,使用共享的 isCancelled 标志。函数内部轮询检查(e.g., 在 setInterval 或 Promise 链中)。

代码示例

javascript 复制代码
let isCancelled = false;  // 全局/作用域标志

// 修改 createHistoryWays(简化版,无需 signal)
async function createHistoryWays(routes) {
  if (isCancelled) return;
  if (!Array.isArray(routes) || routes.length === 0) return;
  
  // 模拟内部检查(如果 routePlan 不可取消,这里只能停止后续链)
  try {
    const result = await gisManager.getGis().routePlan(routes);
    if (isCancelled) {
      clearHistoryRoutes();  // 撤销
      return;
    }
    // UI 更新...
  } catch (err) {
    if (isCancelled) clearHistoryRoutes();
    throw err;
  }
}

// 在 .then 中
.then(async (res) => {
  // ... 数据处理 ...

  const timeoutId = setTimeout(() => {
    isCancelled = true;
    clearAllUI();  // 立即撤销
  }, 20000);

  try {
    await createHistoryWays(multiHistoryWayPoints);
    if (isCancelled) return;  // 停止后续
    
    createFmePeoplelcon(fmePeopleLocation);
    if (isCancelled) return;
    
    await createWaytoTarget(multiCurToTargetWays);
  } catch (err) {
    // 处理错误
  } finally {
    clearTimeout(timeoutId);
    isCancelled = false;  // 重置
  }
});

执行时机和影响

  • 终止时机 :20s 后设置 isCancelled = true,后续 await resolve 后检查并停止。UI 在检查点清除。
  • 优点 :简单,无需修改 routePlan;适用于纯 JS 环境。
  • 缺点 :不精确(如果 routePlan 在后台继续运行,无法真正中断;需在 routePlan 内部添加检查,但复杂)。轮询开销小,但不优雅。
  • 适用 :快速原型;如果 routePlan 是黑盒。
3. 事件驱动方法:使用 CustomEvent 或 PubSub 库

对于复杂应用,使用事件系统(e.g., 原生 CustomEvent 或库如 EventEmitter)触发取消。

代码示例(简要):

javascript 复制代码
// 发布/订阅
document.addEventListener('cancelOperation', () => {
  isCancelled = true;  // 或触发清除
  clearAllUI();
});

// 触发:setTimeout(() => document.dispatchEvent(new CustomEvent('cancelOperation')), 20000);
// 在函数中:addEventListener('cancelOperation', () => { clearHistoryRoutes(); });

执行时机和影响

  • 终止时机:事件触发后,监听器立即清除 UI 并设置标志停止后续。
  • 优点:解耦(UI 按钮可直接触发);易扩展到多组件。
  • 缺点:需管理事件监听器(避免内存泄漏);不直接取消 Promise。
  • 适用:UI 重应用(e.g., React/Vue 中用 hooks 监听事件)。
总体建议和注意事项
  • 最佳实践 :优先 AbortController,它最可靠且可撤销 UI(通过 catch 中的清除)。测试时,模拟 routePlan 延迟(await new Promise(r => setTimeout(r, 30000)))和 abort。
  • UI 撤销挑战:确保跟踪所有更新的元素(e.g., 用数组存储 ID/引用)。如果地图库有事务支持(e.g., undo stack),用它简化清除。
  • 错误处理 :在取消时日志记录(e.g., console.log('Cancelled at 20s')),并通知用户(e.g., toast 消息)。
  • 性能影响:取消后,GIS 服务可能仍有残留请求(取决于服务器);监控网络(DevTools)。
  • 限制 :如果 routePlan 是不可取消的第三方(e.g., 阻塞式),只能 "软取消"(停止等待 + 清除 UI),后台可能继续消耗资源。考虑替换为支持取消的实现。
  • 测试:在 10s/20s 点手动触发取消,验证 UI 恢复原状和后续不执行。

如果提供 gisManager.getGis().routePlan 的具体实现或 UI 库细节,我可以给出更精确的代码。

相关推荐
wangjialelele5 小时前
Linux匿名管道和命名管道以及共享内存
linux·运维·网络
禁默5 小时前
Linux 之从硬件硬盘到文件系统的全面过渡
linux·运维·服务器
塵觴葉6 小时前
Linux内核网络的连接跟踪conntrack简单分析
linux·网络·conntrack
m0_464608266 小时前
监控 Linux 服务器资源
linux
tongsound6 小时前
ros2 lifcycle介绍
linux·c++
☆璇6 小时前
【Linux】Linux环境基础开发工具使用
linux·运维·服务器
鹿鸣天涯6 小时前
CentOS系统停服,系统迁移Ubuntu LTS
linux·运维·centos
半桔7 小时前
【Linux手册】管道通信:从内核底层原理到使用方法
java·linux·服务器·网络·c++
weixin_456904277 小时前
CentOS与Ubuntu的详细区别
linux·ubuntu·centos