在GEE编写代码的时候,客户端和服务器端的代码不能混用。那么什么时候在客户端?什么时候在服务器端呢?
比喻:写菜谱(客户端) vs. 大厨在厨房做菜(服务器端)
-
你(客户端 / Client): 你在你的电脑前,用浏览器里的 JavaScript 代码编辑器写“菜谱”。这个菜谱描述了要做什么菜(比如“年度水体面积变化图”),需要什么“原料”的规格(哪个卫星数据 l8、哪个区域 geometry、哪个时间段 year),以及详细的“烹饪步骤”(过滤 filter、应用水体算法 waterMask、计算面积 reduceRegion、画图 ui.Chart)。
-
你的电脑(浏览器)负责运行这些写菜谱的 JavaScript 代码,组织逻辑,定义参数。
-
速度快,适合处理简单的逻辑、用户界面交互。
-
没有原料和专业厨具:你的电脑没有海量的卫星数据,也没有强大的并行计算能力。
-
-
Google 的服务器(服务器端 / Server): 就像一个拥有巨大食材库(PB 级的卫星数据)和专业自动化厨房(分布式计算集群)的大厨团队。
-
他们接收到你写好的“菜谱”(你通过 GEE API 发送的计算指令)。
-
他们根据菜谱,在自己的厨房里,用自己的食材和设备,实际地进行烹饪(执行数据筛选、计算、分析)。
-
计算能力强,可以并行处理大量数据。
-
直接接触数据。
-
具体来说,在 GEE 代码中:
什么时候是在“客户端” (你的浏览器)?
标准的 JavaScript 代码执行:
-
定义变量:var year = 2020;, var threshold = 0.5;, var coords = […];
-
控制流语句:if (…) {…}, for (…) {…}, while (…) {…} (这些循环和判断本身在浏览器运行)
-
打印到控制台:print('Starting analysis…');
-
创建 UI 元素:var chart = ui.Chart…; print(chart); (创建图表对象本身,并请求显示)
-
调用地图函数:Map.setCenter(…), Map.addLayer(…) (这些函数调用本身在客户端发起,告诉服务器要做什么)
-
定义 GEE 对象和操作(写菜谱步骤): 当你写 var l8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2'); 或 var filtered = l8.filterBounds(geometry); 时,这行 JavaScript 代码是在客户端执行的。它创建了一个叫做 l8 或 filtered 的代理对象 (proxy object)。这个对象本身很小,它只是一个指向服务器端数据或计算指令的引用,就像菜谱上的一个步骤名称。这时并没有真正处理数据。
什么时候是在“服务器端” (Google 的服务器)?
执行 GEE 的计算密集型操作:
-
当你请求结果时,服务器才开始根据你之前定义的“菜谱”(代理对象链)进行计算。请求结果的方式包括:
-
Map.addLayer(eeObject, …):服务器需要计算 eeObject 才能在地图上渲染瓦片。
-
eeObject.getInfo():明确要求服务器计算 eeObject 并将结果(通常是少量数据,如一个数字、一个小列表/字典)返回给客户端浏览器。
-
eeObject.evaluate(function(result) {…}):类似 getInfo(),但异步执行,结果在回调函数中返回给客户端。
-
Export.image.toDrive(…) / Export.table.toDrive(…) 等:要求服务器执行计算并将结果保存到你的 Google Drive 等。
-
-
函数作为参数传递给 GEE 方法时:当你把一个 JavaScript 函数传递给像 .map() 或 .iterate() 这样的 GEE 方法时,这个函数的内容会被发送到服务器,并在服务器上对集合中的每个元素执行。
collection.map(function(image) {
// 这部分代码将在服务器上对 collection 中的每个 image 执行
var processed = image.multiply(2).add(1);
return processed;
});content_copydownload
Use code with caution.JavaScript
-
执行 reduceRegion, reduceColumns, classify, expression 等分析函数: 这些复杂的计算显然发生在服务器端。
-
执行 ee.Algorithms.If: 条件判断和分支选择都在服务器端进行。
关键点和易混淆处:
-
延迟执行 (Deferred Execution): 定义 GEE 对象和操作链(写菜谱)并不会立即执行计算。计算被推迟到你明确请求结果(如 getInfo, Map.addLayer)时才在服务器上触发。
-
代理对象 (Proxy Objects): 客户端的 ee.Image, ee.Number, ee.FeatureCollection 等变量只是服务器端实际数据或计算的引用/占位符。
-
.getInfo() 是桥梁(但要小心使用): 它是将服务器计算结果拉回客户端的方式。但因为它需要等待服务器响应,会阻塞浏览器,并且传输数据可能很慢,所以绝对不能在服务器端函数(如 .map() 内部)或客户端循环内部频繁使用。
-
.map() 内是服务器端: 传递给 .map() 的函数体是在服务器上运行的,所以它不能包含需要与客户端交互的操作(如 getInfo())。但它可以访问传递给它的服务器端参数(如 image)和从客户端传入并在服务器端表示的变量。
总结:
-
客户端(浏览器):负责编排任务(写菜谱)、定义参数、处理用户界面、发起请求、处理少量返回结果。运行标准 JavaScript。
-
服务器端(Google):负责执行繁重的计算、访问海量数据、并行处理。运行由 GEE API 调度的计算任务。
理解这个分离是避免写出低效或错误代码(尤其是涉及 .getInfo() 误用)的基础。尽可能让计算保留在服务器端,只在必要时才将少量结果取回客户端。
评论前必须登录!
注册