精华内容
下载资源
问答
  • 本文转自机器之心,禁止二次转载对于一些刚入门 Python 的朋友来说,代码稍微复杂些就难以搞懂代码内部到底是怎么运行的了,而且有时一运行就报错,难以一下发现错误,只...
        

     本文转自机器之心,禁止二次转载 

    对于一些刚入门 Python 的朋友来说,代码稍微复杂些就难以搞懂代码内部到底是怎么运行的了,而且有时一运行就报错,难以一下发现错误,只会用 Print 去慢慢找异常的地方,效率很低下。

    所以对程序进行监控和调试很重要。今天就给大家分享一个由国外大神制作的 Python 神工具,可以实时动态地监控 Python 程序的运行情况,逐行追踪代码的运行时间,整个过程是可视化的,这就很赞了啊,能一清二楚地了解程序运行情况,有异常时也能快速找到,节省大量时间。


    640

    项目地址:https://github.com/alexmojaki/heartrate

    640

    Heartate——如监测心率般追踪程序运行

    这个工具库叫 Heartrate ,可以实时可视化 Python 程序的执行过程。监控运行中的 Python 程序如图:


    640?wx_fmt=gif


    如图所示,左侧数字表示每行代码被触发的次数。长方框表示最近被触发的代码行——方框越长表示触发次数越多,颜色越浅表示最近被触发次数越多。

    虽然追踪每行代码的触发次数是一个方法,但是要是能计算每次触发代码的执行时间就好了。这样能够更好地说明哪行代码是效率瓶颈。by 思

    得益于 executing (https://github.com/alexmojaki/executing) 库,当前被执行的调用以高亮显示。

    实时堆栈追踪(stacktrace)如下所示:


    640?wx_fmt=gif


    640

    功能


    该工具可以:

    • 启动程序追踪

    • 在线程中启动服务器

    • 打开显示 trace() 被调用的文件可视化图的浏览器窗口

    在文件视图中,堆栈追踪位于底部。而在堆栈追踪中,用户可以点击正在追踪文件的堆栈条目,从而在该代码行打开文件的可视化图。

    trace 只追踪调用它的线程。若要追踪多线程,用户必须在每个线程都予以调用,并且每次的端口也不同。

    640

    如何设置需要监测的程序

    files 确定了除调用的 trace 之外其他需要追踪的文件。files 必须是可调用的,并接受一个参数:文件路径,同时如果应该追踪该文件,则需要返回 True。为方便起见,这位开发者提供了以下函数:

    • files.all:追踪所有文件;

    • files.path_contains(substrings):追踪路径中包含任何给定子字符串的所有文件;

    • files.contains_regex(pattern):追踪自身包含给定正则表达式(regex)的所有文件,所以用户可以在源代码中标记所追踪的文件,如添加注释。

    默认情况下追踪包含注释 # heartrate 的文件(空格可选)。

    如果用户要追踪多个文件,则可通过以下两种方式得到它们的可视化页面:

    • 在堆栈追踪中,用户点击正在追踪的堆栈条目,则可以打开页面并跳转至堆栈条目;

    • 跳转至 http://localhost:9999/ 网站的索引页,从而查看追踪文件列表。

    host:服务器的 HTTP host。若要运行可从任何地方访问的远程服务器,使用'0.0.0.0'。默认为'127.0.0.1'。

    port:服务器的 HTTP 端口。默认为 9999。

    browser:若为 True,则自动打开显示文件(trace 被调用)可视化图的浏览器标签。默认为 False。

    640

    安装



    pip install --user heartrate


    支持 Python 3.5 以上版本。

    640

    其他代码可视化工具

    除了上面这个外,还有一个可以可视化代码执行过程的网站,名为 Pythontutor和本文的 Heartrate 不同,该网站更多的是可视化数据在程序中的变化过程。

    可视化的过程如下:


    640?wx_fmt=gif


    用户还可以在网站上编辑修改代码,观察运行过程中数据的变化。同时该网站还有 Java 等其他语言的版本。

    640

    网站地址:http://www.pythontutor.com (http://www.pythontutor.com/)


    640

    参考链接:https://github.com/alexmojaki/heartrate

    往期回顾

    640?wx_fmt=jpeg

    有趣的灵魂在等你

    点个在看smiley_66.png

    展开全文
  • > fragment我们经常使用到的一个控件,但是,相信大家会出现这样的一个问题,每次切换fragment的时候,fragment就会重新调用一次生命周期的方法,从而会重新加载一次数据,这样既消耗用户的数据流量和机器性能;...

    fragment是我们经常使用到的一个控件,但是,相信大家会出现这样的一个问题,每次切换fragment的时候,fragment就会重新调用一次生命周期的方法,从而会重新加载一次数据,这样既消耗用户的数据流量和机器性能; 现在就教大家一个方法,来解决这个问题; 之前我们一直都是这样写的代码:

    /**
         * 根据传入的参数来改变当前的fragment
         *
         * @param fragment
         */
        private void showFragment(Fragment fragment) {
            FragmentTransaction transaction = fragmentManager.beginTransaction();
            transaction.replace(R.id.main_fl_content, fragment);
            transaction.commit();
        }

    翻看了Android官方文档,发现,replace()这个方法只是在上一个Fragment不再需要使用时采用的简便方法。正确的切换方式是add(),切换时hide(),add()另一个Fragment;再次切换时,只需hide()当前,show()另一个。(这也是谷歌官方推荐的做法)

     /**
         * 修改显示的内容 不会重新加载
         * to 下一个fragment
         * mContent 当前的fragment
         */
        private void switchContent(Fragment to) {
            if (mContent != to) {
                FragmentTransaction transaction = fragmentManager
                        .beginTransaction().setCustomAnimations(android.R.anim.fade_in, R.anim.slide_out);
                if (!to.isAdded()) { // 判断是否被add过
                    // 隐藏当前的fragment,将 下一个fragment 添加进去
                    transaction.hide(mContent).add(R.id.main_fl_content, to).commit(); 
                } else {
                    // 隐藏当前的fragment,显示下一个fragment
                    transaction.hide(mContent).show(to).commit(); 
                }
    
                mContent = to;
            }
    
        }
    
    
    
    展开全文
  • 本文转自机器之心,禁止二次转载对于一些刚入门 Python 的朋友来说,代码稍微复杂些就难以搞懂代码内部到底是怎么运行的了,而且有时一运行就报错,难以一下发现错误,只会用 Print 去慢慢找异常的地方,效率很低下...

     本文转自机器之心,禁止二次转载 

    对于一些刚入门 Python 的朋友来说,代码稍微复杂些就难以搞懂代码内部到底是怎么运行的了,而且有时一运行就报错,难以一下发现错误,只会用 Print 去慢慢找异常的地方,效率很低下。

    所以对程序进行监控和调试很重要。今天就给大家分享一个由国外大神制作的 Python 神工具,可以实时动态地监控 Python 程序的运行情况,逐行追踪代码的运行时间,整个过程是可视化的,这就很赞了啊,能一清二楚地了解程序运行情况,有异常时也能快速找到,节省大量时间。

    978ae80dc0d5b4cf1515e206a1949749.png

    项目地址:https://github.com/alexmojaki/heartrate

    7363e39022f48efa6388266b72a711f5.gif

    Heartate——如监测心率般追踪程序运行

    这个工具库叫 Heartrate ,可以实时可视化 Python 程序的执行过程。监控运行中的 Python 程序如图:

    78703145ffabd30212afea80395ac19f.gif

    如图所示,左侧数字表示每行代码被触发的次数。长方框表示最近被触发的代码行——方框越长表示触发次数越多,颜色越浅表示最近被触发次数越多。
    虽然追踪每行代码的触发次数是一个方法,但是要是能计算每次触发代码的执行时间就好了。这样能够更好地说明哪行代码是效率瓶颈。by 思
    得益于 executing (https://github.com/alexmojaki/executing) 库,当前被执行的调用以高亮显示。实时堆栈追踪(stacktrace)如下所示:

    39040aaf8c10096250775d1faef4d2a7.gif

    7363e39022f48efa6388266b72a711f5.gif

    功能

    该工具可以:
    • 启动程序追踪

    • 在线程中启动服务器

    • 打开显示 trace() 被调用的文件可视化图的浏览器窗口

    在文件视图中,堆栈追踪位于底部。而在堆栈追踪中,用户可以点击正在追踪文件的堆栈条目,从而在该代码行打开文件的可视化图。trace 只追踪调用它的线程。若要追踪多线程,用户必须在每个线程都予以调用,并且每次的端口也不同。7363e39022f48efa6388266b72a711f5.gif

    如何设置需要监测的程序

    files 确定了除调用的 trace 之外其他需要追踪的文件。files 必须是可调用的,并接受一个参数:文件路径,同时如果应该追踪该文件,则需要返回 True。为方便起见,这位开发者提供了以下函数:
    • files.all:追踪所有文件;

    • files.path_contains(substrings):追踪路径中包含任何给定子字符串的所有文件;

    • files.contains_regex(pattern):追踪自身包含给定正则表达式(regex)的所有文件,所以用户可以在源代码中标记所追踪的文件,如添加注释。

    默认情况下追踪包含注释 # heartrate 的文件(空格可选)。如果用户要追踪多个文件,则可通过以下两种方式得到它们的可视化页面:
    • 在堆栈追踪中,用户点击正在追踪的堆栈条目,则可以打开页面并跳转至堆栈条目;

    • 跳转至 http://localhost:9999/ 网站的索引页,从而查看追踪文件列表。

    host:服务器的 HTTP host。若要运行可从任何地方访问的远程服务器,使用'0.0.0.0'。默认为'127.0.0.1'。port:服务器的 HTTP 端口。默认为 9999。browser:若为 True,则自动打开显示文件(trace 被调用)可视化图的浏览器标签。默认为 False。7363e39022f48efa6388266b72a711f5.gif

    安装

    pip install --user heartrate
    支持 Python 3.5 以上版本。7363e39022f48efa6388266b72a711f5.gif

    其他代码可视化工具

    除了上面这个外,还有一个可以可视化代码执行过程的网站,名为 Pythontutor和本文的 Heartrate 不同,该网站更多的是可视化数据在程序中的变化过程。可视化的过程如下:

    68b3c60a1e44aa72c5758f3fadb5b5ec.gif

    用户还可以在网站上编辑修改代码,观察运行过程中数据的变化。同时该网站还有 Java 等其他语言的版本。978ae80dc0d5b4cf1515e206a1949749.png

    网站地址:http://www.pythontutor.com (http://www.pythontutor.com/)

    978ae80dc0d5b4cf1515e206a1949749.png

    参考链接:https://github.com/alexmojaki/heartrate

    往期回顾
    • 普林斯顿博士:手写30个主流机器学习算法,全都开源了!

    • 资深程序员骆昊:Python从新手到大师,100天完整学习路线

    • 推荐一款数据处理的神级工具,完全结合了Python和Excel的优势

    7c0a4208d7c2be26698d777589a5f6aa.png有趣的灵魂在等你

    点个在看62ea5685567fb7e2acb1b2d3cf2c85de.png

    展开全文
  • 在这一篇文章中, 我希望能够用最简单明了的语言去解释 JavaScript 代码是如何执行的.# 基础概念解析## 编译原理首先我们要知道, 我们写的代码是给人看的, 机器是看不懂的. 为了代码可以被机器...

    5094f313fac00523cafaac01b6487fdd.png

    # 前言

    作为还在漫漫前端学习路上的一位自学者。我以学习分享的方式来整理自己对于知识的理解,同时也希望能够给大家作为一份参考。希望能够和大家共同进步,如有任何纰漏的话,希望大家多多指正。感谢万分!


    在这一篇文章中, 我希望能够用最简单明了的语言去解释 JavaScript 代码是如何执行的.

    # 基础概念解析

    ## 编译原理

    首先我们要知道, 我们写的代码是给人看的, 机器是看不懂的. 为了让代码可以被机器执行, 需要将代码转换为机器语言. "编译型语言" 是先将所有代码编译完成之后, 才开始执行. JavaScript 是 "解释型语言", 它会在程序的运行过程中进行编译. 在代码执行前极短的时间内将其转换成机器语言.

    JavaScript 的编译过程分为两个阶段:编译期 & 执行期

    在 "编译期" 阶段, 由解释器完成, 它主要分为下面几个步骤:

    1. 词法分析: 将由代码分解成(对编程语言来说)有意义的代码块,这些代码块被称为 "词法单元". 例如,var a = 2; 这段程序通常会被分解成为下面这些词法单元: var, a, =, 2, ;.
    2. 语法分析: 将 "词法单元" 转换为一代表了程序语法结构的树结构, 被称为 "抽象语法树" .
    3. 生成可执行代码: 将抽象语法树转换成机器可以执行的代码.

    在 "执行期" 阶段, 由 JavaScript 引擎完成, 主要分成以下步骤:

    1. 创建执行上下文: 执行上下文用以描述代码执行时所处的环境. 在后文我会详细讲述;
    2. 执行代码: 执行上下文创建完之后, 处于内部的代码会被引擎逐句执行;

    ## 作用域

    作用域可以理解为一套规则, 它定义了变量和函数的可访问范围,控制着变量和函数的可见性与生命周期.

    作用域可分为, 静态作用域, 或者动态作用域. JavaScript 采用词法作用域 (lexical scoping), 也就是静态作用域。

    • 静态 (词法) 作用域: 静态作用域在代码的 "词法分析" 阶段就确定了. 变量的可访问范围取决于源代码, 与程序的执行流程没关系. 作用域的确定不需要程序运行, 只通过静态分析就可以.
    • 动态作用域: 动态作用域是根据程序的运行动态确定的. 动态作用域并不关心变量和函数是如何声明以及在何处声明的, 它只关心他们是在何处被调用的.

    ## 执行上下文

    执行上下文 (execution context), 是一个抽象概念, 用于描述代码执行时所处的作用域环境. 它定义代码语句对变量或函数的访问权.

    在代码的 "执行期", JavaScript 引擎会创建执行上下文. 在 JavaScript 中, 它表现为一个内部对象. 每当 Javascript 代码在运行的时候,它都是在执行上下文中运行。

    JavaScript 中有三种执行上下文:

    • 全局执行上下文: 默认的代码运行环境,一旦代码被载入执行,引擎最先创建的就是这个环境. 不写在函数内的代码, 被执行时处于全局执行上下文.
    • 函数执行上下文: 写在函数内的代码运行时, 处于函数执行上下文.
    • eval 执行上下文: 作为 eval 函数参数的代码, 运行时处于 eval 执行上下文. 这里略过不讲.

    在函数被调用之前, 函数的执行上下文会被创建. 在创建过程中, 主要做如下三件事:

    1. 创建变量对象
    2. 创建作用域链;
    3. 确定 this 指向;

    在下文里, 我会逐一介绍.


    ## 调用栈 (执行环境栈)

    JavaScript 引擎用以追踪函数执行流的一种机制

    当执行环境中调用了多个函数时,通过这种机制,我们能够追踪到哪个函数正在执行,执行的函数体中又调用了哪个函数。

    它遵循 "先进后出" 的栈结构. 第一个被创建, 并推入栈的一定为 "全局执行上下文". 之后, 当一个函数要被调用之前, JavaScript 引擎会为它创建 "函数执行上下文", 然后压入调用栈中。

    当函数执行完毕, 函数的执行环境被从栈中弹出销毁, 把控制权交给之前的执行环境. 即使是同一个函数, 它每次被调用时, 都会创建一个单独的执行上下文.

    到最后, 全部代码执行结束, "全局执行上下文" 被弹出栈销毁.

    举例说明:

    var a = "Hello World!";
    
    function first() {
      console.log("1");
      second();
      console.log("1 again");
    }
    
    function second() {
      console.log("2");
    }
    
    first();
    console.log("0");
    
    // 结果: 1 -> 2 -> 1 again -> 0
    

    上面代码里, 执行上下文在执行栈中被推入和销毁顺序为:

    d3934d0935bb2ec75eee7cd16450ef8e.png

    ## 变量对象 / 活动对象

    ### 变量对象 (Variable Object)

    在创建执行上下文的时候, 变量对象会被创建. 执行上下文中的所有变量声明, 函数声明都会被扫描出来, 然后在变量对象上创建同名属性. 如果是在函数执行上下文中的话, 变量对象里还包括了函数的形参集合.

    通过变量对象, 执行上下文就可以知道自己有哪些数据. 这个对象是给 JavaScript 引擎用的, 开发者不可以访问到.

    函数执行上下文中, 变量对象的创建,依次经历了以下几个过程:

    1. 创建 arguments 对象. 检测函数调用时所处上下文传入的参数, 在该对象下创建属性, 和初始化属性值;
    2. 扫描函数内的所有函数声明:
    3. 为每一个函数声明,在变量对象上创建一个同名属性, 属性值为函数在内存中的引用;
    4. 如果已有同名属性存在, 则属性值被重写覆盖为新函数的引用;
    5. 扫描函数内的变量声明:
    6. 为每一个变量声明, 在变量对象创建一个同名属性, 属性值初始化为 undefined;
    7. 如果已有同名属性存在, 为防止同名函数被重写为 undefined. 变量声明会被跳过, 原属性值不会被修改;

    等函数中的代码被 JavaScript 引擎执行时, 具体的变量赋值才会进行.

    举例说明:

    function a() {
      console.log(b); // function b() {}
    
      var b = 123;
    
      function b() {}
    
      console.log(b); // 123
    }
    
    a();
    

    在执行 b = 123 这句赋值语句之前, 变量对象中的 b 属性的值为函数. 但赋值语句让 b 属性的值被改写成了 123. 在创建变量对象阶段里, fucntion b 声明被先处理, var b 声明被跳过. 请一定要分清执行上下文的创建阶段, 和代码执行阶段.

    ### 活动对象 (Activation Object)

    前文说, 执行上下文被创建完后, 会被推入执行栈的顶部, 然后 JavaScript 引擎开始逐行执行里面的代码.

    活动对象, 和变量对象其实指的都是同一个对象, 但只有在执行栈顶部的执行上下文中的变量对象里的属性才可以被访问, 它也就被称为 "活动对象".

    ### 变量提升

    在了解了变量对象的创建流程之后, 变量提升就很容易被理解啦. 因为在代码被执行之前, 变量声明, 函数声明已经先被扫描出来, 并在变量对象中创建同名属性了. 所以在代码执行阶段, 即使在变量声明之前去获取变量也是可以的. 只不过那个时候, 变量赋值还没被执行, 变量的值为 undefined.


    ## 作用域链

    作用域链, 由当前执行上下文和它上层的执行上下文的 "变量对象" 组成, 它保证了当前执行环境对符合访问权限的变量和函数的有序访问。

    在创建函数执行上下文的时候, 作用域链会被建立.

    举例说明:

    var a = 5;
    
    function fun() {
      var b = a + 1;
    
      function innerFun() {
        var c = 10;
        console.log(b + c);
      }
    
      innerFun();
    }
    
    fun();
    

    上面的代码运行时, 全局执行上下文, fun 函数执行上下文, innerFun 执行上下文被依次创建, 推入执行栈. 设定他们的变量对象分别为 VO(global),VO(fun), VO(innerFun). 那么 innerFun 的作用域链, 同时包含这三个变量对象.

    我们可以直接用一个数组来表示 innerFun 的作用域链:

    [VO(innerFun), VO(fun), VO(global)];
    

    作用域链会保存在函数的内部属性 [[Scope]] 上. 内部属性供 JavaScript 引擎使用, 开发者是访问不到这个属性的.


    ## this

    this 指向是函数执行时所在的环境对象. 在函数被调用前, 创建执行上下文的过程中被确定. 之后在函数执行的过程中, this 的指向已经被确定,就不可更改了.

    ### 全局中的 this

    在全局执行上下文中, this 指向它自身, 也就是全局对象. 在浏览器中为 window 对象, 在 Node 中为 global 对象

    ### 函数中的 this

    前面说, this 指向是函数执行时所在的环境对象. 简单来说, 函数的 this 指向它的调用者. 如果函数被一个对象所拥有, 该函数被对象调用时, this 指向该对象. 如果函数独立调用, this 的值为 undefined. 非严格模式下, 当 this 的值为 undefined 时, 它会被自动指向全局对象.

    举例说明:

    var val = 0;
    
    var obj = {
      val: 1,
      fn: function() {
        console.log(this.val);
      }
    };
    
    var fn_2 = obj.fn;
    
    obj.fn(); // 1, this 指向 obj
    fn_2(); // 0, this 指向 window
    

    上例中, 即使 fn_2fn 指向同一个函数. 但是 fn_2 为独立调用, this 的值为 undefined, 在非严格模式下, 指向 window.

    ### 显式改变 this 指向

    通过 call, apply, bind, 我们可以显式的执行函数执行上下文的 this 指向.

    var val = 0;
    
    var obj = {
      val: 1
    };
    
    function fn() {
      console.log(this.val);
    }
    
    fn(); // 0
    fn.call(obj); // 1
    

    这里就不再赘述各种方法的使用细节了, 大家可以自行查阅文档.

    ### 构造函数 & 原型方法的 this

    前面所说的 this 绑定都是在直接调用函数的情况下. 当使用 new 操作符调用构造函数创建对象实例的时候, this 绑定又是怎么样的呢? 构造函数的原型方法中的 this 又指向何处呢?

    function Animal(name, sound) {
      this.name = name;
      this.sound = sound;
    }
    
    Animal.prototype.yell = function() {
      return this.sound;
    };
    
    var Cat = new Animal("猫", "喵喵");
    console.log(Cat.name); // 猫
    console.log(Cat.yell()); // 喵喵
    

    在通过 new 操作符调用构造函数时, 会经历以下四个阶段:

    1. 创建一个新的对象;
    2. 构造函数的 this 指向新对象;
    3. 为这个新对象添加构造函数中的属性和方法;
    4. 返回新对象

    也就是说, 构造函数中的 this 指向这个新创建的实例对象.

    而原型方法做为一个函数, 它被实例对象调用, 那它的 this 也就指向这个实例对象.


    # 事件循环

    下面所讲的是浏览器当中的事件循环

    ## 单线程

    首先我们要知道, JavaScript 的最大特点就是 "单线程". 也就是说同一时间只能处理一个操作.

    那么为什么要这样设计呢? JavaScript 作为浏览器的脚本语言, 主要用途是来处理用户交互, 以及操作 DOM. 这使得多线程的设计会导致很复杂的同步问题. 举例说, 如果 JavaScript 可以同时操纵两个线程. 一个线程添加在某个 DOM 节点上添加内容, 另一个线程在这个 DOM 节点下删除内容. 那么浏览器, 该听谁的呢? 所以 JavaScript 被设计成了单线程的.


    ## 同步任务 & 异步任务

    单线程就意味着任务必须要排队, 一个一个得等待被执行. 那很明显的一个问题是, 如果有一个任务耗时过长, 那后面的任务就必须要等待. 如果是任务的计算量太大, 设备 CPU 处理能力不够, 必须耗时很长, 那还可以理解. 但如果任务是从网络中读取数据, 因为网速慢, 或其他原因导致等待响应时间过长, 那必然会导致程序运行效率, 和 CPU 利用率非常低下.

    所以 JavaScript 的另一个特点就是 "非阻塞 I/O", 也称 "异步式 I/O". 当主线程遇到 I/O 操作时 (磁盘读写, 网络通信),不会以阻塞的方式等待 I/O 操作的完成, 或数据的返回. 而只是将 I/O 操作交给浏览器,然后自己继续执行下一条语句。 当浏览器完成 I/O 操作时,会将用以处理 I/O 操作结果的处理函数推入到一个任务队列, 等待主线程后续进行处理.

    于是任务就分成, "同步任务", 和 "异步任务" 两种.

    • 同步任务: 在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
    • 异步任务: 主线程交给浏览器去执行. 执行完毕后, 将用以处理异步操作结果的处理函数, 推入 "任务队列", 等待主线程处理.

    ## 任务队列 & 事件循环

    前面说过执行上下文创建完, 会被推入调用栈. JavaScript 引擎会逐句执行最顶部的执行上下文中的代码.

    在执行过程中, 同步任务逐句被执行. 当遇到了异步任务, JavaScript 引擎会将它们交给浏览器上对应的 Web API 去处理. 比如 Ajax 请求, 会被交给 Network 模块. 浏览器处理完毕之后, 会将用以处理结果的处理函数 (回调函数), 推入到任务队列中.

    当调用栈中只剩全局执行上下文的时候, 主线程就会去查询任务队列了. 任务队列中的任务会被逐一取出放入调用栈执行. 当处理任务的时候, 又遇到了新的异步任务, 则会重复之前的操作. 也就是, 调用对应 Web API, 处理完毕后, 回调函数添加到任务队列末尾.

    上面的步骤会一直重复, 直到任务队列完全清空了, 至此程序执行完毕. 而这个循环过程就被叫做 "事件循环".

    473e36d82f43aceab9b007de3d98bc90.png

    ## 宏任务 & 微任务

    上面只是笼统的说了下 "异步任务" 和 "任务队列" 的概念. 在浏览器中, 异步任务分成 "宏任务" (macro-task) 和 "微任务" (micro-task) 两种. 这两种任务也都各自有一条任务队列.

    • 宏任务: 包括 script(整体代码), setTimeout, setInterval, setImmediate,requestAnimationFrame, I/O, UI rendering.
    • 微任务: 包括 process.nextTick, Promise, Object.observe, MutationObserver

    第一次事件循环从宏任务 (macro-task) 开始. 我们看到整体的 script 代码也算是一个宏任务. 那么从读取整体 script 代码开始算第一次循环.

    之后全局执行上下文被创建, 推入执行栈. 直到最后执行栈只剩全局执行上下文时, 线程然后执行所有的 micro-task 队列中的任务. 清空后, 线程从 macro-task 队列首部取一个任务, 然后到最后再清空 micro-task 队列.

    之后再去 macro-task 队列去下一个任务. 这样一直循环, 直到 macro-task, micro-taks 队列都清空了, 全局执行上下文出栈, 程序结束.

    举例说明:

    // 同步任务
    console.log("0");
    
    setTimeout(function() {
      // 宏任务
      console.log("1");
    
      new Promise(function(resolve, reject) {
        // 同步任务
        console.log("2");
        resolve();
      }).then(() => {
        // 微任务
        console.log("3");
      });
    }, 0);
    
    new Promise(function(resolve, reject) {
      // 同步任务
      console.log("4");
      resolve();
    }).then(() => {
      // 微任务
      console.log("5");
    });
    
    // 同步任务
    console.log("6");
    
    // 最后结果: 0, 4, 6, 5, 1, 2, 3
    

    # 参考

    • 你不知道的 JavaScript (上卷)
    • 掘金 - polkYu - 浅析 JavaScript 的事件循环机制
    • JavaScript 作用域、上下文、执行期上下文、作用域链、闭包
    • 掘金 - 子非 - [译] 理解 JavaScript 中的执行上下文和执行栈
    • 深入理解 JavaScript 执行上下文、函数堆栈、提升的概念
    • 深入了解 JavaScript,从作用域链开始(1)
    • 九死蚕传人 bo - 前端基础进阶(四):详细图解作用域链与闭包
    • 九死蚕传人 bo - 前端基础进阶(十二):深入核心,详解事件循环机制
    • RuGuo_09 - 为什么 javascript 是单线程?
    展开全文
  • 在这一篇文章中, 我希望能够用最简单明了的语言去解释 JavaScript 代码是如何执行的.# 基础概念解析## 编译原理首先我们要知道, 我们写的代码是给人看的, 机器是看不懂的. 为了代码可以被机器...
  • 编译运行的原理其实大致类似,下面我们看下具体流程:一、 源文件的编译执行流程链接(linking)将各种代码和数据片段收集并组合成一个单一文件的过程, 这个文件可被加载到内存并执行。...
  • 那么,我们很容易发现一个问题,我们写出来的高级语言的代码是怎么一步一步变成机器码,从而让机器可以执行的呢?本文主要论述如下问题: 1. AT&T指令的基本知识 2.分支和循环的机器级实现 3. 函数的调用的机
  • 01 即时编译优化Java程序在运行初期通过解释器来执行,当发现某块代码运行特别频繁,就会将之判定为热点代码(Hot Spot Code), 虚拟机会将这部分代码编译成本地机器码,并对这些代码进行优化。这件事就是即时编译...
  • 剧照 |《春光灿烂猪八戒》之前的文章《源代码如何被计算机执行》已经提到计算机只能执行二进制的机器码,C、C++等编译型语言依靠编译器将源代码转化为可执行文件后才能运行,Python、Java等解释型语言...
  • Mysql默认不可以通过远程机器访问的,通过下面的配置可以开启远程访问。在MySQL Server端:执行mysql 命令进入mysql 命令模式, Sql代码mysql> use mysql; mysql> GRANT ALL ON *.* TO admin@'%' IDENTIFIED ...
  • 机器学习算法介绍

    2021-01-27 16:14:03
    计算机程序,指为了得到某种结果而可以由计算机(等具有信息处理能力的装置)执行的代码化指令序列(或者可以被自动转换成代码化指令序列的符号化指令序列或者符号化语句序列)。通俗讲,计算机给人干活,但它不是...
  • 机器学习之算法介绍

    2021-02-25 12:14:43
    计算机程序,指为了得到某种结果而可以由计算机(等具有信息处理能力的装置)执行的代码化指令序列(或者可以被自动转换成代码化指令序列的符号化指令序列或者符号化语句序列)。通俗讲,计算机给人干活,但它不是...
  • 机器学习算法

    2017-12-30 15:10:09
    计算机程序,指为了得到某种结果而可以由计算机(等具有信息处理能力的装置)执行的代码化指令序列(或者可以被自动转换成代码化指令序列的符号化指令序列或者符号化语句序列)。 通俗讲,计算机给人干活,但它...
  • 当然比如创建文件和访问网络这些危险的API并没有真正的在本机执行,而是通 过传回虚假的返回值来欺骗shellcode其平稳运行。 直接命令行输入scdbg.exe example.sc 来看看输出: 其中example.sc文件就是以二进制...
  • 并且通过异常堆栈丢失这一常见的现象来进行举例即时编译优化Java程序在运行初期通过解释器来执行,当发现某块代码运行特别频繁,就会将之判定为热点代码(Hot Spot Code), 虚拟机会将这部分代码编译成本地机器码,...
  • python的程序在python解释器...实际上,解释器是代码机器的计算机硬件之间的软件逻辑层。当Python包安装在机器上后,它包含了一些最小化的组件:一个解释器和支持的库。根据使用情况的不同,Python解释器可能采...
  • 详细内容我们怎么让计算机去读取并执行Python代码文件呢?python解释器什么?Python语言编程语言,计算机能听懂的语言。计算机的大脑CPU, 中文名叫中央处理器,它仍然不能直接处理 Python 语言。CPU 只能...
  • 用任何编程语言来开发程序,都为了计算机干活,比如下载一个MP3,编写一个文档等,而计算机干活的CPU只认识机器指令,所以,尽管不同的编程语言差异极大,最后都得"翻译”成CPU可以执行的机器指令。而不同...
  • 该资料《Visual C++ 2008入门经典》的源代码及课后练习答案 对应的书籍资料见: Visual C++ 2008入门经典 基本信息 原书名: Ivor Horton's Beginning Visual C++ 2008 原出版社: Wrox 作者: (美)Ivor Horton ...
  • 我们怎么让计算机去读取并执行Python代码文件呢?python解释器什么?Python语言编程语言,计算机能听懂的语言。计算机的大脑CPU, 中文名叫中央处理器,它仍然不能直接处理 Python 语言。CPU 只能直接处理...
  • 什么程序(Program)计算机程序,指为了得到某种结果而可以由计算机(等具有信息处理能力的装置)执行的代码化指令序列(或者可以被自动转换成代码化指令序列的符号化指令序列或者符号化语句序列)。通俗讲,...
  • 用任何编程语言来开发程序,都为了计算机干活,比如下载一个MP3,编写一个文档等,而计算机干活的CPU只认识机器指令,所以,尽管不同的编程语言差异极大,最后都得“翻译”成CPU可以执行的机器指令。而不同的...
  • 当你编写了一段python程序,python解释器将读取程序,并按照其中的命令执行,得出结果,实际上,解释器是代码机器的计算机硬件之间的软件逻辑层。通俗来说,我们的计算机基于二进制进行运算的,无论你用什么语言...
  • python解释器什么

    2019-12-19 01:38:19
    我们怎么让计算机去读取并执行Python代码文件呢?python解释器什么? Python语言编程语言,计算机能听懂的语言。 计算机的大脑CPU, 中文名叫中央处理器,它仍然不能直接处理 Python 语言。 CPU 只能...
  • 什么python解释器

    2020-11-24 14:48:19
    上面的Python代码文件,我们怎么让计算机去读取并执行呢? 刚才我们说Python语言编程语言,计算机能听懂的语言。 计算机的大脑CPU, 中文名叫中央处理器,它 仍然不能直接处理 Python 语言。 CPU 只能直接...
  • 味道怎样,咬一口就知道,...编译器作用就是将一种计算机无法理解的文本,转译成计算机能执行的语句,我们要做的编译器如下,将带有加法和乘法的算术式子,转译成机器执行的汇编语句,例如语句: 1+2*3+4, 经过编译后

空空如也

空空如也

1 2 3 4 5
收藏数 96
精华内容 38
关键字:

代码是怎么让机器执行的