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中了,至此就完成了多线程过滤点的操作。
最后的效果,就是界面不会卡顿。并且点加载的速度也有明显的提升!