1.项目背景:

一个市区面polygon内的点Graphics数组(相当于相交)到GraphicsLayer中并展现在地图中,这其中就需要过滤掉不在这个polygon内的点,因为我用的GraphicsLayer图层。这个图层并没有提供SpatialFilter之类的方法,能够直接过滤。所以只能选择循环一个个的graphics和polygon进行空间相交运算。 因为Javascript是单线程的,所以导致界面会出现明显的卡顿(卡顿1到2s),这肯定是没办法忍受的。所以开始查找多线程资料,希望能在多线程中完成点的加载

   思路1:使用web worker 将 过滤的这个操作,放在多线程中处理,然后将处理后的数据以数组的形式,传回到主线程中,然后再加载到图层中。  经过测试后,发现这种方式,没办法将arcgis api 的对象(例如graphic、geometry)传入到多线程js文件中。传过去这些对象都不是arcgis api 的对象,相应的属性和方法都没有了。然后我就想说,那我可以在传入之前,先将arc api 对象转换成json对象呢?  经过测试,还是不行。

  思路2:继续查找资料。找到了 arcgis api 原来自带worker类 。。。。  兜兜绕绕一圈子,你去藏在api!

require(["esri/core/workers"], function(workers) { /* code goes here */ });

    那么api对这个worker的解释是:                 

This module is a utility framework that simplifies the use of Web Workers in the ArcGIS API for JavaScript

    //个人翻译:这是一个能在arcgis api中能简化使用 web workers 的框架; 其实就是arcgis api 已经封装好了

web worker,就等我们来用了!  

2.使用教程:

    具体的使用方法,这个api 上已经有了详细的解释。我理解的如下:

     step1:首先配置好 你的需要多线程处理的js文件的路径,其中这个esriConfig 是api 的一个模块。也需要引入!其中的wokerDir属性 就是配置着你的多线程js文件夹路径(这里文件夹的名称是我设置的是workerScripts),里面放着的就是多线程要运行的js文件。

// Set worker's loaderConfig to set up
// a path to folder called workersScripts
esriConfig.workers.loaderConfig = {
 paths: {
   workerDir: window.location.href.replace(/\/[^/]+$/, "/workerScripts"),
 }
};

  step2:运行完配置之后,开始加载这个多线程文件,在这里这个filterPointsByPolygon就是我自己写的多线程中要运行的js文件,其中有一个方法叫做getFilterData,这个方法里面就可以写我自己的业务逻辑。

// Load workerScripts/Calculator.js in the workers framework
// and invoke its "max" method

var filterPolygonJSON=self.filterPolygon.toJSON();
workers.open("workerScripts/filterPointsByPolygon")
  .then(function(connection) {
    return connection.invoke("getFilterData", {
      data:self.data,
      polygon:filterPolygonJSON
    });
  })
  .then(function(result) {
    console.log(result);
  });

对象中的属性和方法都没法使用,浏览器不识别。

会再次回到主线程中的异步方法中,也就是上面的这个then方法,其中的result参数,就是我们多线程js文件传回来 的 已经过滤好的 js数组。

step3:在多线程文件中,我们还是按照 dojo ADM模块写法。来定义个这个多线程js文件,

define(["esri/core/promiseUtils",
        'workerDir/common/js/GeometyHelper',
        'esri/geometry/Point',
        'esri/geometry',
        'esri/geometry/polygon',
        'esri/layers/FeatureLayer',
        'esri/layers/support/Field',
        'esri/Graphic',
        'workerDir/Config/serverUrl'
        ], 
        function(promiseUtils,GeometryHelper,Point,Geometry,Polygon,
        			FeatureLayer,Field,Graphic,serverUrl) {


     var filterPointsByPolygon= function filterPointsByPolygon(){};

     filterPointsByPolygon.prototype.max = function(data) {
         var resultData=[];、
         //接受主线程传过来的参数
         var sourceData=data.data;
         //重新将filterPOlygonJSON转换成arcapi 中的Polygon对象
         var filterPolygon=Polygon.formJSON(data.filterPOlygonJSON);

          
            过滤数据代码

         

      //返回过滤后的数组
      return resultData;

    }
    //返回 filterPointsByPolygon实例
    return filterPointsByPolygon;
})

      这里面还需要注意的是,如果我们需要在多线程js文件中 加载我们自定义的js模块的话,应该怎么办?比如上面代码中我们要加载这个   /common/js/GeometyHelper'   文件。那么还记得我们最开始的时候定义的wokerspripts文件路径吗。这个路径最开始是直接指向了多线程js文件夹。那么我们可以把这个路径往上层路径设置,这样的话,这个路径加上我们拼接的路径。就可以访问到我们的程序中放置在common/js文件夹下的GeometryHelper文件了。其他文件访问类似。

step4:  等到子线程中把过滤后的数据返回到主线程中的then方法中。那么我们就可以将所有点组成graphics添加到graphicsLayer中,然后add到Map中了,至此就完成了多线程过滤点的操作。

 

最后的效果,就是界面不会卡顿。并且点加载的速度也有明显的提升!