资讯专栏INFORMATION COLUMN

《JavaScript Cookbook 2nd》之 Function

doodlewind / 2902人阅读

摘要:函数调用会在内存形成一个调用记录,又称调用帧,保存调用位置和内部变量等信息。等到运行结束,将结果返回到,的调用帧才会消失。在进入内层函数的时候,可以直接用内层函数的调用帧替换掉外层函数的调用帧,从而大大减少内存占用。

昨晚翻了一下,虽然都是一些旧知识,不过深入下去对照着其他资料一起看,还是能发现一些有意思的地方。

函数式编程

反正之前我是没搞懂函数式和命令式的区别,也很疑惑函数式编程中,如果出现分支怎么办,昨晚总算弄明白了。

// 我们有4个基础函数,会根据不同的业务逻辑进行组装使用
// 自动创建
function autoCreate () {}
// 自动同步
function autoSync () {}
// 流程 A
function processA () {}
// 流程 B
function processB () {}
// 流程 A 与流程 B 在业务上是互斥的

传统的命令式编程,我们会这样写业务逻辑

function service (errorHandler) {
  
  var result;

  if (!id) {
    result = autoCreate();
    if (result.error) {
      errorHandler(result);
    }
  }

  if (type === "a") {
    processA();
    if (result.error) {
      errorHandler(result);
    }
  }

  if (type === "b") {
    result = processB();
    if (result.error) {
      errorHandler(result);
    }
  }

  if (!isSync) {
    result = autoSync();
    if (result.error) {
      errorHandler(result);
    }
  }
}

而函数式编程,我们则可以这样写业务逻辑。

// service 本身不是一个异步业务,所以直接使用 Promise.resolve()
var service = Promise.resolve();

// 需要对autoCreate()等四个基础函数做 Promise 改造
service.then(autoCreate)
       .then(processA)
       .then(processB)
       .then(autoSync)
       .catch(errorHandler);

这里可能会有一个疑惑,互斥的 processA 和 processB 怎么进入了同一个处理流程,这样和需求就不符合了?

在这种情况下,我们还需要在 processA 和 processB 的内部,把退出条件补上。

function processA () {
  return new Promise(function(resolve, reject){

    if (type !== "A") {
      resolve();
    }

    // 这里继续 processA 的逻辑代码

  });
}
调用栈

JS 在执行的时候,有一个函数调用栈,栈里面放着一个个的函数调用帧,这些帧保存着所属函数所需的所有变量信息。

函数调用会在内存形成一个“调用记录”,又称“调用帧”(call
frame),保存调用位置和内部变量等信息。如果在函数A的内部调用函数B,那么在A的调用帧上方,还会形成一个B的调用帧。等到B运行结束,将结果返回到A,B的调用帧才会消失。如果函数B内部还调用函数C,那就还有一个C的调用帧,以此类推。所有的调用帧,就形成一个“调用栈”(call
stack)。

浏览器拦截 window.open

我们发现有时候执行 window.open(),能正常打开新窗口或者新的标签页,而有时却又不行,会被浏览器拦截。

其原因是浏览器会根据当前调用栈,找到最初的caller,如果不是用户触发的,则拦截。

尾调用优化

由于函数调用的时候会生成新的调用帧,当递归调用的时候,调用栈中的调用帧增长会非常厉害,最终导致内存耗尽而触发 RangeError。

如果把函数调用放在函数块的最后一条语句,且不在使用外层函数的变量了,则外层函数所占用的调用帧已无存在意义。在进入内层函数的时候,可以直接用内层函数的调用帧替换掉外层函数的调用帧,从而大大减少内存占用。

其他

Partial Application 的模式,用来做 Library 和 SDK 都挺好的。一个可定制性高的底层接口,再通过类似 _.partial() 的方式,提供一个开箱即用的上层接口。就像 $.ajax()$.get() 一样。

_.defer()_.memoize() 可以用在有大运算量的业务场景。

同步于我的博客

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86549.html

相关文章

  • 【译】JavaScript数据结构(3):单向链表与双向链表

    摘要:计算机科学中最常见的两种数据结构是单链表和双链表。双向链表双向链表具有单链表的所有功能,并将其扩展为在链表中可以进行双向遍历。双向链表的操作我们的链表将包括两个构造函数和。与单链表不同,双向链表包含对链表开头和结尾节点的引用。 翻译:疯狂的技术宅英文:https://code.tutsplus.com/art...说明:本文翻译自系列文章《Data Structures With Ja...

    Chiclaim 评论0 收藏0
  • Jquery Cookbook摘要使用上下文参数

    摘要:你已经听说过上下文参数,但是还没有碰到使用的场合。传递一个选择器表达式,一个对象,一个集合,或者一个节点给上下文参数,将尽在这个上下文中搜索元素。 你已经听说过上下文参数,但是还没有碰到使用的场合。再想$()中,传递选择器的时候,可以传递第二个参数,指定上下文,jQ将在这个上下文中搜索匹配选择器表达式的元素,上下文参数可能是利用最不充分的JQ功能,其用法非常简单。传递一个选择器表达式,...

    EasonTyler 评论0 收藏0
  • 数据结构JavaScript描述(二)

    摘要:在上一篇文章中,我们了解了队列和栈的描述,现在让我们来了解一下单链表和双向链表的实现。单链表和双向链表具有以下特点可动态分配空间,但不能随机访问。 在上一篇文章中,我们了解了队列和栈的JavaScript描述,现在让我们来了解一下 单链表 和双向链表 的实现。本文的代码并非所有都由本人所写,只是出于学习目的,在此分享出来,并加上一定的解释,便于大家学习。 本系列文章的代码可在ht...

    OldPanda 评论0 收藏0
  • 资源大放送

    摘要:这是我收集的一些资源,分享给大家,全部放在百度网盘,有需要的请转存到自己的网盘或者下载,以免网盘链接失效,另外还有几百的视频文件存在网盘,需要的加全部分享在空间,自己可以去下载与权威指南配套源码禅意花园高清源码基础教程权威指南参考手册锋利 这是我收集的一些资源,分享给大家,全部放在百度网盘,有需要的请转存到自己的网盘或者下载,以免网盘链接失效,另外还有几百G的视频文件存在网盘,需要的加...

    lidashuang 评论0 收藏0
  • Laravel 中缓存驱动的速度比较

    摘要:我们很容易修改缓存驱动方式。这样的话,我们甚至根本不必检查缓存是否过期。与驱动相比,和的速度更快,所以建议在项目较大时使用外部缓存驱动。结论使用文件数据库作为驱动,两者在速度上没有很明显的区别。所以投资高速缓存是值得的。 showImg(https://segmentfault.com/img/remote/1460000014057714?w=1440&h=720); 缓存是web开...

    go4it 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<