02-入门知识点-异步请求操作Promise

地图应用开发过程中,客户端经常需要和GIS服务器数据通讯,传统的方式是客户端发送一个请求给服务器端,然后等待服务器返回结果再做下一步的代码执行,也就是同步方式。但是现在,很多情况下是建议采用异步的方式,这样设计的好处是当任务执行时,程序还可以同时执行其他的业务逻辑(譬如我们可能需要同时执行多个服务器请求),不需要一直等待服务器端返回结果,这能提供更好的地图使用体验。目前互联网大部分的应用都采用异步方式,关于异步的好处这里就不过多阐述。这里要重点介绍的是ArcGIS API for JavaScript 4.x(简称API)关于异步操作promise的使用。
Promise字面上理解就是承诺,既然承诺了就要去执行,不管成功还是失败,都要把结果告诉对方,不能杳无音信。这个其实挺适合异步操作这种场景,客户端发送请求给服务器,客户端知道服务器把结果返回,所以它可以先去干其他的事,等结果回来了,再处理。Esri提供的这套API就是采用promise这种机制来满足上述的需求。简单来说promise有三种状态,pending, resolved, rejected。当结果执行成功时,状态为resolved,同时调用回调函数callback 来执行程序定义的代码。当执行失败的时候,状态为rejected,同时调用回调函数errback 来执行程序定义的代码,譬如告示用户友好的错误信息。Promise的常用格式如下:
这里写图片描述
譬如下面的例子:
这里写图片描述
除了上面这种方式之外,我们还可以用otherwise函数来处理请求错误的的情况:
这里写图片描述
虽然使用的方式不一样,但是作用都是一样,所以在开发的时候,团队内部订好一种作为规范即可。下面的例子点坐标投影转换,具体我们可以先看下代码:

require([
  "esri/tasks/GeometryService",
  "esri/tasks/support/ProjectParameters", ...
  ], function(GeometryService, ProjectParameters, ... ) {

    // Create a new instance of GeometryService
    var gs = new GeometryService("http://sampleserver6.arcgisonline.com/arcgis/rest/services/Utilities/Geometry/GeometryServer" );
    // Set up the projection parameters
    var params = new ProjectParameters({
          geometries: [points],
          outSR: outSR,
          transformation = transformation
    });

    // Run the project function
    gs.project(params).then(function(projectedGeoms){
          // The promise resolves to the value stored in projectedGeoms
          console.log("projected points: ", projectedGeoms);
          // Do something with the projected geometries inside the .then() function
    }, function(error){
          // Print error if promise is rejected
          console.error(error);
    });
});

在这段代码中主要是试用API的GeometryService的porject方法来执行坐标转换,而执行的过程是在线的几何服务,也就说把点坐标数据传递给在线的几何服务,几何服务在处理完之后,把结果返回客户端。我们看整个异步请求的操作过程其实很简单,在project函数后面跟.then函数即可。
试想一下,如果我们基于上面的这个例子进行再进一步执行其他的操作,譬如在执行完坐标转换之后,对返回的点数据进行缓冲分析,缓冲的范围之后再添加到客户端地图上展示,之后计算每个缓冲范围的面积,最后再计算全部的缓存范围的面积。这上面的每一个步骤都是环环相扣,如果按常规的异步操作写法,那么下一个步骤的逻辑代码需要上一个步骤的then函数中,对于代码的可读性来说还是比较复杂。幸运的是,在API中提供了chain promises的模式来满足多个步骤环环相扣执行的情景,简单说就是在上一个.then函数之后再跟上下一个步骤的.then函数,具体可以参考以下的代码片段:

// Creates instance of GraphicsLayer to store buffer graphics
  var bufferLayer = new GraphicsLayer();

/** Project the points and chain the promise to other functions
When project() resolves, the points are sent to bufferPoints()
When bufferPoints() resolves, the buffers are sent to addGraphicsToBufferLayer()
When addGraphicsToBufferLayer() resolves, the buffer geometries are sent to calculateAreas()
When calculateAreas() resolves, the areas are sent to sumArea()
**/
  gs.project(params).then(bufferPoints) 
.then(addGraphicsToBufferLayer)
.then(calculateAreas) 
    .then(sumArea)
    .otherwise(function(error){ 
      console.error('One of the promises in the chain was rejected! Message: ', error);
    });

// Note how each function returns the value used as input for the next function in the chain
  // Buffers each point in the array by 1000 feet
  function bufferPoints(points) {
    return geometryEngine.geodesicBuffer(points, 1000, 'feet');
  }

  // Creates a new graphic for each buffer and adds it to the bufferLayer
  function addGraphicsToBufferLayer(buffers) {
    buffers.forEach(function(buffer) {
      bufferLayer.add(new Graphic(buffer));
    });
    return buffers;
  }

  // Calculates the area of each buffer and adds it to a new array
  function calculateAreas(buffers) {
    return buffers.map(function(buffer) {
      return geometryEngine.geodesicArea(buffer, 'square-feet');
    });
  }

// Calculates the sum of all the areas in the array returned from the previous then()
  function sumArea(areas) {
    var total = 0;
    areas.forEach(function(area) {
      total += area;
    });
    console.log("Total buffered area = ", total, " square feet.");
  }

在上面的这段代码中,每个功能点都做了封装,有坐标转换、缓冲分析、计算面积以及合算总面积,然后通过.then函数的连接,把每个功能点都串在了一起,最终既达到环环相扣的业务需求,又提高了程序代码的可读性。
上面讲到的都是执行了某个对象的方法之后,异步等待执行结果的情景。有没有针对对象的异步处理promise机制?其实也是有的,API中提供了直接在对象的后面跟上.when()函数的模式,来满足对象层面的异步处理情景。一个很典型的情景就是:在地图都加载完成之后,应用才开始执行其他操作。当然,也不是API的所有对象都支持这种promises。目前能提供这种promises机制的有以下的对象:
这里写图片描述
看完这几个对象,其实也就明白,如果遇到需要在地图或者图层都加载完成之后进行其他操作的情况,那么就可以在这些对象的后面跟上.when()函数,譬如下面这个例子:
这里写图片描述
这个例子就是我们前面说的,在基础地图加载完成之后,再去执行其他的业务逻辑。当然你可能会问,这种机制是Esri创造的吗?其实不是,如果对于这块比较感兴趣的话可以看下 MDN Promise documentation 和the Dojo Promise documentation ,具体链接如下:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
http://dojotoolkit.org/reference-guide/1.10/dojo/promise/Promise.html#dojo-promise-promise

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值