探索Sass3.3中的Maps(二):SassMaps和Memoization

本文由大漠根据Micah Godbolt的《Exploring Maps In Sass 3.3(Part 2): Sass Maps & Memoization》一文所译,整个译文带有我们自己的理解与思想,如果译得不好或不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://www.phase2technology.com/blog/sass-maps-memoization/,以及作者相关信息。

——作者:Micah Godbolt

——译者:大漠

在介绍Sass Maps的博客系列中,第一篇文章主要介绍了Sass3.3 引入了Sass Maps,而在第二部分(这篇文章),我将向大家阐述Sass Maps更强大用途之一:memoization。Memoization技术已经常期用于其他语言当中,以来提高性能。它涉及到一个函数结果的缓存,是这样的,如果一个函数使用相同的的参数调用两次,那么缓存的副本可以用来替代需要再次计算的值。

话说,我们有现个简单的函数的调用是这样的:

$length1: length(cat, dog, fish);
$length2: length(cat, dog, fish);

在这种情况之下,Sass的length()函数会对列表list(cat,dog,fish)调用两次,可每次计算的长度都是3。

如果你对Sass提供的函数不太了解,建议你先阅读一下《Sass函数》。——@大漠

这种计算的开销显然是相当小的,但我们考虑一个不同的功能:

// Fibonacci Function

@function fibonacci($n) {
 $fib: 0 1;
 @for $i from 1 through nth($n,1) {
   $new: nth($fib, length($fib)) + nth($fib, length($fib) - 1);
   $fib: append($fib, $new);
 }
 @return $fib;
}

这就是著名的斐波那契(Fibonacci)函数,他创建了一串数字,每个数字是两个预览数的总和。这个函数可以接受多秒钟编译每次使用的功能,想像一下这样的情况:

$fib1: fibonacci(1000);
$fib2: fibonacci(1000);

你让Sass执行完全是相同的,耗费的时间,计算两次。我怀疑你会需要一个斐波那契数列,很多时候,你的网格系统使用了一个函数来制作,它可能会在单个的项目中调用上百次。

Maps允许我们使用Memoization技术,这样当我们调用fibonacci(1000)第二次时,我们也不需再计算该值。相反,我们将这些值存储在Maps中,我们需要的时候就可以调用。

如何在项目中创建Memoization

你可以通过此链接打开一个示例,接下来的内容,我们根据这个示例内容进行阐述。

我们先创建一个全局的变量$memo,并且赋予其一个空的map:

$memo:();

第一件事情是就是创建一个辅助函数memo-update():

@function memo-update($function, $params, $value) {
 $result:();
 @if map-has-key($memo, $function) {
   $sub-map-new: map-merge(map-get($memo,$function),($params: $value));
   $result: map-merge($memo, ($function: ($sub-map-new) ));
 }
 @else {
   $result: map-merge($memo, ($function: ($params: $value)));
 }

 @return $result;
}

这个函数的功能就是检查函数中是否有条目@if map-has-key($memo,$function)。如果有则更新sub-map,并且创建新的条目;如果没有则创建一个新的sub-map。然后返回新的$memo,并且更新了$memo Maps。

我们来创建第二个辅助函数memo-get():

@function memo-get($function, $params) {
  $result: map-get(map-get($memo,$function),$params);
  @return $result;
}

这个函数实现通过$function的Key在$memo的Map中得到自己的需,然后通过参数$params的Key在map-get($memo,$function)新产生的Map中得到自己的值。看起来蛮复杂的一样。

最后是我们系统的心脏:call-function()。这个函数调用了前面定义的两个函数。

@function call-function($function, $params...) {
  @if map-has-key($memo, $function) {
      $result: memo-get($function, $params);
      @if $result != null {
          @return $result;
      }
  }
  $result: call($function, $params...);
  $memo: memo-update($function, $params, $result) !global;
  @return $result;
}

当给函数传递参数之后,call-function()会检查以前是否有调用过。如果有,将会通过memo-get()函数检索值。如果之前没用,则使用call()函数,返回结果,并通过memo-update()来重组$memo map。

有了这些功能,我们可能通过call-function()或其他函数名以及参数列表。他会从$memo的map中索引出值,就算没有,也可以计算出值,并更新到$memo的map中。

还有很多我们可以做的,而且应该做的,用这些东西可以使其更加强大。

在下周我将会结束Map的这个系列教程。通过这个系列教程,我们可以改善Sass的Maps和如何调用我们的变量,使用变量。在此期间,我阅读了Mike Crittenden系列教程

这篇文章个人理解起来蛮复杂的。似懂非懂。希望没有带来太多的误导。——@大漠

译者手语:整个翻译依照原文线路进行,并在翻译过程略加了个人对技术的理解。如果翻译有不对之处,还烦请同行朋友指点。谢谢!

出处:

英文出处:http://www.phase2technology.com/blog/sass-maps-memoization/

中文译文:http://www.w3cplus.com/preprocessor/sass-maps-memoization.html