JS篇JavaScript-执行上下文和提升

我们通常将 JavaScript 归类为动态或解释执行语言,但实际上它也是一门编译语言,它有自己的编译器形式,运行在 JavaScript 引擎中。 每个 Web 浏览器都有自己的 JavaScript 引擎形式:Chrome 有 V8,Mozilla 有 SpiderMonkey 等。这些 JavaScript 引擎的共同点都是将 JavaScript 代码转换为编译器可以理解的语言,然后执行它。 执行上下文 Execution Context当 JavaScript 代码运行的时候,运行 JavaScript 代码的环境形成了执行上下文 ,执行上下文决定代码可以访问哪些变量、函数、对象等。 我们将执行上下文简单视为运行当前代码的 environment / scope,我们知道作用域分为 global scope 和 local scope。 类似的,执行上下文也分为不同的类型: 全局执行上下文 - 代码首次执行时候的默认环境,在代码的整个执行过程中,只用一个全局执行上下文。 函数执行上下文 - 每当执行流程进入到一个函数体内部的时候,就会创建一个函数执行上下文,可以有任意数量的函数执行上下文。 执行栈/调用栈JavaScript 是单线程的,浏览器只分配给 JavaScript 一个主线程,一次只能执行一个任务(函数),因此它在执行栈中对其他操作(事件和函数执行)形成一个任务队列,排队等候执行。 每当在浏览器中加载脚本时,栈 stack 中的第一个元素就是全局执行上下文。当有函数执行时,将创建一个函数执行上下文,并将其置于全局执行上下文之上。一旦函数执行完成,它就会从执行堆栈中弹出,并将控制权交给它下面的上下文中。结合上面说到的,我们看一个例子: var name = "global variable";console.log(name)function func1() { console.log("func1 被调用了。") func2();}function func2() { console.log("func2 被调用了。");}func1(); ...

July 13, 2019 · 2 min · jiezi

Go之context包的分析

context是Go语言官方定义的一个包,称之为上下文。 Go中的context包在与API和慢进程交互时可以派上用场,特别是在提供Web请求的生产级系统中。在哪里,您可能想要通知所有goroutines停止工作并返回。 这是一个基本教程,介绍如何在项目中使用它以及一些最佳实践和陷阱。 先决条件在了解上下文之前,请先了解以下概念 goroutinechannelContext在Go语言中 context 包允许您传递一个 "context" 到您的程序,如超时或截止日期(deadline)或通道(channel),以及指示停止运行和返回等。例如,如果您正在执行Web请求或运行系统命令,那么对生产级系统进行超时控制通常是个好主意。因为,如果您依赖的API运行缓慢,您不希望在系统上备份请求,这可能最终会增加负载并降低您所服务的所有请求的性能。导致级联效应。这是超时或截止日期context可以派上用场的地方。 这里我们先来分析context源码( https://golang.org/src/contex...)。 context包的核心就是Context接口,其定义如下: type Context interface { Deadline() (deadline time.Time, ok bool) Done() <-chan struct{} Err() error Value(key interface{}) interface{}}这个接口共有4个方法: Deadline`方法是获取设置的截止时间的意思,第一个返回式是截止时间,到了这个时间点,Context会自动发起取消请求;第二个返回值ok==false时表示没有设置截止时间,如果需要取消的话,需要调用取消函数进行取消。Done方法返回一个只读的chan,类型为struct{},我们在goroutine中,如果该方法返回的chan可以读取,则意味着parent context已经发起了取消请求,我们通过Done方法收到这个信号后,就应该做清理操作,然后退出goroutine,释放资源。Err方法返回取消的错误原因,因为什么Context被取消。Value方法获取该Context上绑定的值,是一个键值对,所以要通过一个Key才可以获取对应的值,这个值一般是线程安全的。但使用这些数据的时候要注意同步,比如返回了一个map,而这个map的读写则要加锁。以上四个方法中常用的就是Done了,如果Context取消的时候,我们就可以得到一个关闭的chan,关闭的chan是可以读取的,所以只要可以读取的时候,就意味着收到Context取消的信号了,以下是这个方法的经典用法。 func Stream(ctx context.Context, out chan<- Value) error { for { v, err := DoSomething(ctx) if err != nil { return err } select { case <-ctx.Done(): return ctx.Err() case out <- v: } } }Context接口并不需要我们实现,Go内置已经帮我们实现了2个(Background、TODO),我们代码中最开始都是以这两个内置的作为最顶层的partent context(即根context),衍生出更多的子Context。 ...

May 22, 2019 · 5 min · jiezi