精华内容
下载资源
问答
  • 一句话攻略】彻底理解JS的回调(Callback)函数

    万次阅读 多人点赞 2018-03-11 02:55:02
    1. 函数可以作为个参数个函数被调用。 2. JS是异步编程语言,这就是说JS代码的执行顺序并不是从上至按部就班完成的。大多数语言都是同步编程语言,比如现在我们有3行代码,那么系统一定是行按...

    作为JS的核心,回调函数和异步执行是紧密相关的,也是必须跨过去的一道个门槛。

    那么究竟什么是回调函数(Callback),其实回调函数并不复杂,明白两个重点即可:

    1. 函数可以作为一个参数在另一个函数中被调用。

    2. JS是异步编程语言,这就是说JS代码的执行顺序并不是从上至下按部就班完成的。大多数语言都是同步编程语言,比如现在我们有3行代码,那么系统一定是一行一行按顺序向下执行的,第一行执行完了,执行第二行,紧跟着最后执行第三行,你可能会说这不是废话吗?且慢,在JS里则不尽然,比如有3行代码,并不是排在最前面的代码就是最先执行完毕的,很有可能是最后一行语句最先执行完,然后排在最前面的那行反而是最后执行完毕的,所以我们说JS是异步编程语言。

    下面以node.js为例,举一个例子保证你在3步之内搞清楚究竟什么叫回调函数:

    STEP 1:

    var fs = require("fs");
    var c
    
    function f(x) {
        console.log(x)
    }
    
    function writeFile() {
        fs.writeFile('input.txt', '我是通过fs.writeFile 写入文件的内容', function (err) {
            if (!err) {
                console.log("文件写入完毕!")
                c = 1
            }
        });
    }
    
    c = 0
    writeFile()
    f(c)

    以上代码不难理解,就是设置一个全局变量c = 0,然后执行writeFile函数(也就是写入一个文件input.txt),这个函数里面有一行c = 1,函数执行完毕之后再跳出来调用f()函数,f()函数很简单,就是把打印一个变量,仅此而已。

    按照 “正常” 逻辑,首先c=0,然后调用writeFile函数,该函数里面有一句c = 1,最后再调用f(c),又因为调用writeFile()是在f(c)之前,所以c=1这条语句肯定是会被执行到,那么结果应该是打印1,但是万万想不到,结果竟然是0,明明我们在writeFile函数里我们重新对c进行了赋值,为什么结果还是0呢?

    因为程序运行到writeFile()这一行的时候,是一个比较耗时的IO操作,JS碰到这种操作并不会停在原地一直等待直到函数执行完毕,而是直接运行下一条代码(即f(c)),而此时 c = 1这一行代码其实并没有被执行到,所以打印出来的结果还是0 ! 

    那你肯定会说,要解决这个问题还不容易,我们把调用f(c)也放进writeFile函数里面不就行了呗!这样就能保证c = 1之后再调用f(c)了吧?没错,就这么简单:

    STEP 2:

    var fs = require("fs");
    var c
    
    function f(x) {
        console.log(x)
    }
    
    function writeFile() { 
        fs.writeFile('input.txt', '我是通过fs.writeFile 写入文件的内容', function (err) {
            if (!err) {
                console.log("文件写入完毕!")
                c = 1
                f(c)
            }
        });
    }
    
    c = 0
    writeFile() 

    这个代码的逻辑不需要多说了吧,因为实在太简单了,就是把f(c)放进了writeFile()里面,那么c=1必然会被执行到,然后才执行f(c),不用多说,结果肯定是显示为1。但是改成这样并不完美,因为这么做就相当于将f()"焊死"在writeFile()里了,如果此处我最终想调用的函数不是f()而是别的其他函数咋整?难不成要写几个不同的writeFile(),而他们之间的区别仅仅是最后调用的那个函数不同?这样也太笨了吧,于是今天的主角:“关键字” callback 登场了。(准确地说callback并不真的是Javascript里的关键字,但是鉴于大家都约定成俗把callback这个单词作为回调函数的默认选择了,这里姑且就不严谨地称它为"关键字"吧)

    STEP 3:

    var fs = require("fs");
    
    function f(x) {
        console.log(x)
    }
    
    function writeFile(callback) { //callback,表示这个参数不是一个普通变量,而是一个函数
        fs.writeFile('input.txt', '我是通过fs.writeFile 写入文件的内容', function (err) {
            if (!err) {
                console.log("文件写入完毕!")
                c = 1
                callback(c) // 因为我们传进来的函数名是f(),所以此行相当于调用一次f(c)
            }
        });
    }
    var c = 0
    writeFile(f) // 函数f作为一个参数传进writeFile函数

    经过改造后的代码出现了两次callback,第一个callback出现在writeFile的形参里,起定义的作用,表示这个参数并不是一个普通变量,而是一个函数,也就是前面所说的重点1,即所谓的“以函数为参数”。 第二个callback出现在c = 1下面,表示此处“执行”从形参传递进来的那个函数。这样一来,writeFile()函数在执行完毕之后到底调用哪个函数就变“活”了,如果我们想writeFile()函数执行完之后并不是像第二个例子那样只能调用f(),而是还有别的函数比如说x() y() z(),那么只需要写成 writeFile(x),writeFile(y)... 就行了。

    我相信你已经看明白上面的代码,因为实在并不高深,那么我们现在开始用一句话攻略做一个总结:

    在大多数编程语言中,函数的形参总是从外向内传递参数,但在JS中,如果形参碰到“关键字” callback 则完全相反,它表示从内向外反向调用某个外部函数。

    PS: 此处并不一定非要写为“callback”,你可以任意写成abc, iloveyou...等等随你高兴。callback只是一种约定俗成的写法,它明确地告诉代码阅读者:此处是一个回调函数。

    有时候,我们会看到一些函数的形参列表里直接嵌套一个函数的情况,其本质上仍然是回调函数,因为没有了函数名,所以也称匿名函数。

    如本例如果要写成这种风格的话就是长成这样了:

    var fs = require("fs");
    
    function writeFile(callback) { 
        fs.writeFile('input.txt', '我是通过fs.writeFile 写入文件的内容', function (err) {
            if (!err) {
                console.log("文件写入完毕!")
                c = 1
                callback(c) 
            }
        });
    }
    var c = 0
    writeFile(function (x) {
        console.log(x)
    })

    writeFile()函数不变,只是在调用它的时候,直接将函数体嵌在参数列表里了,其作用跟上一个例子完全一样。其实在本例中,fs.writeFile函数后面也有一个匿名回调函数 function (err) {},这个函数表示当文件写入完毕后,就回调它,如果在写入过程中出现了错误,则通过变量err携带出来。我相信有了前面的铺垫,您已经肯定能理解它的含义了,事实上这种写法在JS里是出现频率最高的主流风格。

    【补充】在JS里,当然也并非所有操作都是异步的,比如for循环,无论这个for循环需要耗时多长,系统也一定会等它转完之后才会执行下面的语句。我所了解的会产生异步执行的操作大概有以下几种:

    定时器、建立网络连接、读取网络流数据、向文件写入数据、Ajax提交、请求数据库服务,等等。

    如果至此你还是没弄清楚到底什么是回调函数,那么绝不是您的问题,而一定是我的表达有不足之处,欢迎留言探讨!

     

    展开全文
  • 百度知道的答案: 比如显示图像的驱动程序,多个程序的显示都是需要他来执行。 我们玩游戏算一个程序,需要显示图像的驱动,声音驱动...然后你在执行一个命令行,顺序调用这两个程序,就会实现一个剪切文件的功能...
    百度知道的答案:
    比如显示图像的驱动程序,多个程序的显示都是需要他来执行。
    我们玩游戏算一个程序,需要显示图像的驱动,声音驱动、IO驱动的同时执行。
    就这么简单。

    我的理解:大家知道bat文件可以当做命令call的。
    你写了一个实现了拷贝的功能的bat文件,又写了一个实现删除功能的bat文件,这就是两个程序了。
    然后你在执行一个命令行,顺序调用这两个程序,就会实现一个剪切文件的功能。
    于是你剪切文件的这个一个进程就执行了你的这两个程序。

    其实这个东西咋一看不好理解,主要是人们总觉得程序应该是一个界面完整、包含业务逻辑和数据的软件。而在这句话中,一个函数就是一个程序了,程序片段也算程序。
    展开全文
  • (1)顺序块的语句是条接条按顺序执行的,只有前面的语句执行完成之后才能执行后面的语句(除了带有内嵌延迟控制的非阻塞赋值语句)。 (2)如果语句包括延迟或事件控制,那么延迟总是相对于前面那条语句执行完成的...

    顺序块:


    关键字begin - end用于将多条语句组成顺序块。顺序块具有以下特点:

    (1)顺序块中的语句是一条接一条按顺序执行的,只有前面的语句执行完成之后才能执行后面的语句(除了带有内嵌延迟控制的非阻塞赋值语句)。

    (2)如果语句包括延迟或事件控制,那么延迟总是相对于前面那条语句执行完成的仿真时间的。

    在[例5. 9]中进一步给出了两个顺序块语句的例子。顺序块之中语句按顺序执行,[例5.9]的说明1中,在仿真0时刻x、y、z、w的最终值分别为0、1、1、2(十进制)。执行这4个赋值语句有顺序,但不需要执行时间。在说明2中,这4个变量的最终值也是0、1、1、2,但块语句完成时的仿真时刻为35,因为除第一句外,以后每执行一条语句都需要等待。

    【例5.9】顺序块

    //说明1

    reg x,y;
    reg [1:0] z,w;
    
    initial
    begin
         x=1'b0;
         y=1'b1;
         z={x,y};
         w={y,x};
    end
    

    //说明2:带延迟的顺序块

    reg x,y;
    reg [1:0] z,w;
    
    initial
    begin
         x=1'b0;      //在仿真时刻0完成
         #5 y=1'b1;   //在仿真时刻5完成
         #10 z={x,y}; //在仿真时刻15完成
         #20 w={y,x}; //在仿真时刻35完成
    end
    

    并行块


    并行块由关键字fork-join声明,它的仿真特点是很有趣的。并行块具有以下特性:

    (1)并行块内的语句并发执行;

    (2)语句执行的顺序是由各自语句内延迟或事件控制决定的;

    (3)语句中的延迟或事件控制是相对于块语句开始执行的时刻而言的。

    注意:顺序块和并行块之间的根本区别在于:当控制转移到块语句的时刻,并行块中所有的语句同时开始执行,语句之间的先后顺序是无关紧要的。请考虑[例5.9]中带有延迟的顺序块语句,并且将其转换为一个并行块。转换后的Verilog 代码见[例5.10]。 除了所有语句在仿真0时刻开始执行以外,仿真结果是完全相同的。这个并行块执行结束的时间第20个仿真时间单位,而不再是35个。

    【例5.10】并行块

    //举例1:带延迟的并行块

    reg x, y;
    reg[1:0] z,w;
    
    initial
         fork
              x = 1'b0;     //在仿真时刻0完成
              #5 y=l'bl;    //在仿真时刻5完成
              #10 z={x,y};  //在仿真时刻10完成
              #20 w={y, x}; //在仿真时刻20完成
    join
    

    并行块为我们提供了并行执行语句的机制。不过在使用并行块时需要注意,如果两条语句在同一时刻对同-一个变量产生影响,那么将会引起隐含的竞争,这种情况是需要避免的。下面给出了[例5.9]中说明1的并行块描述。在这段代码中故意引人了竞争。所有的语句在仿真0时刻开始执行,但是实际的执行顺序是未知的。在这个例子中,如果x= 1’b0和y=1’b1两条语句首先执行,那么变量z和w的值为1和2;如果这两条最后执行,那么z和w的值都是2’bxx。因此执行这个块语句后z和w的值不确定,依赖于仿真器的具体实现方法。从仿真的角度来讲,并行块中的所有语句是一起执行的,但是实际上运行仿真程序的CPU在任一时刻只能执行一条语句,而且不同的仿真器按照不同的顺序执行。因此无法正确的处理竞争是目前所使用的仿真器的一个缺陷,这一缺陷并不是并行块所引起的。例如:

    //故意引入竞争条件的并行块

    reg x,y;
    reg [1:0] z,w;
    
    initial
    fork
         x = 1'b;
         y = 1'b1;
         z={x,y};
         w={y,x};
    join
    

    可以将并行块的关键字fork看成是将-一个执行流分成多个独立的执行流;而关键字join,则是将多个独立的执行流合并为一个执行流。每个独立的执行流之间是并发执行的。

    展开全文
  • 多个操作语句的触发器为什么在执行时,只执行了第一句? 这个问题困扰了我好久,记得第一次遇到这个问题是半个月前,做牛腩新闻发布系统的数据库遇到这个问题,是关于级联删除的:当我们删除新闻类别的时候,由于...

    多个操作语句的触发器为什么在执行时,只执行了第一句?

    这个问题困扰了我好久,记得第一次遇到这个问题是半个月前,做牛腩新闻发布系统的数据库遇到这个问题,是关于级联删除的:当我们删除新闻类别的时候,由于外键的原因,我们无法删除新闻类别下有新闻内容的记录,但是通过如下触发器,我们就可以实现:

    create trigger trigcategorydelete
    
    on category
    
    instead of delete
    
    as
    
    begin
    
    declare @id int  --定义一个变量id
    
    select @id=id from deleted  --从deleted临时表中,赋值id给变量@id
    
    delete news where caId=@id  --先删除该类别下的所有新闻
    
    delete category where id=@id  --然后删除新闻类别 
    
    end

    当时学习这里的时候,重点在“级联删除”。看完视频后,根据对触发器的理解,自己写的触发器,如下:

    -- =============================================
    -- Author:		<Author,,Name>
    -- Create date: <Create Date,,>
    -- Description:	<删除新闻触发器,因为存在外键,在删除新闻时,需要先删除新闻评论>
    -- =============================================
    ALTER TRIGGER [dbo].[trigDeleteNews] 
       ON  [dbo].[新闻表] 
       instead of delete
    AS 
    BEGIN
    	--声明新闻变量
    	declare @strNewsTitle varchar(10)
    	--删除新闻评论
    	delete 新闻评论表 where 新闻标题=(select 新闻标题 from deleted)
    	--删除新闻
    	delete 新闻表 where 新闻标题=@strNewsTitle
    
    END

    悲剧发生了,我写的触发器,只执行第一条语句:


    第二条语句不执行,也就是说,我删除“新闻”时,只可以把“新闻评论”删除,而新闻却留了下来,这很让人头疼。当时怎么都没有解决掉,然后就把这个问号画到了现在。

    第二次遇到了,只能解决。又翻出数据库,开始折腾。

    终于发现一个问题:这是改正后的触发器,在删除新闻评论,和删除新闻的语句中,都换成了变量,而变量@strnewstitle 在开始就进行了赋值。比较第一次的触发器:首先:变量没有定义,所以第二条语句没有被执行,第一条语句中,么有使用变量,所以执行了。



    总结:问题其实很容易发现,多一点细心就可以了。当时就因为这个“小细节”,是的一个写了90%的触发器不可以使用,做什么都一样,可见细节是必须要重视的。

    而这段时间老是很浮躁,所以,思考问题,发现问题都变得那么的轻浮,把本不该拖拉的工作拖拉了很久,表示惭愧。


    展开全文
  • 一句话+一张图理解——数据结构与算法

    千次阅读 多人点赞 2018-05-18 16:13:45
    一句话: 相互之间存在关系的数据元素的集合就是数据结构,算法是解决特定问题的有限求解步骤。 一张图: 学习数据结构与算法有什么用呢?拿一个厨师的厨艺来比较的话,真正的大厨一般不是那种能做各种花样的菜...
  • 深入理解C语言指针

    万次阅读 多人点赞 2019-09-28 08:36:51
    要知道指针的概念,要先了解变量内存如何存储的。存储时,内存被分为块的。每块都有个特有的编号。而这个编号可以暂时理解为指针,就像酒店的门牌号一样。 1.1、变量和地址 先写段简单的代码: ...
  • 很多的渗透过程,渗透人员会上传一句话木马(简称webshell)到目前web服务目录继而提权获取系统权限,不论asp、php、jsp、aspx都是如此,那么一句话木马到底是如何执行的呢,下面我们就对webshell进行一个简单的...
  • 深入理解Java虚拟机-虚拟机执行子系统

    万次阅读 多人点赞 2020-01-04 17:00:27
    Class 文件的版本常量池访问标志类索引、父类索引与接口索引集合字段表集合方法表集合属性表集合字节码指令简介公有设计和私有实现Class文件...类加载器的特点类加载器的隔离问题破坏双亲委派模型字节码执行引擎...
  • 工作或学习,我们写过很多代码,但往往我们并不了解每行代码都干了些什么。以下给你个简单的实例,你是否会有所触动。注释里是对代码的理解。...//创建了个局部变量i,并给其分配内存 值为1 A ...
  • 理解fork()的次调用两次执行

    千次阅读 2016-12-02 21:48:06
    fork()函数是linux里多进程编程的基础,为linux成为...但是对于很多初学者而言,虽然知道怎么写多进程的程序,知道怎么fork()出个子进程,却很少有人能够理解fork()的最有特点的个性质:次调用,两次执行
  • 看该篇文章前,我推荐了另外一篇博客,看完再来看该篇博客。...接下来,就来分析为什么AsyncTask只能被执行一次: public final AsyncTask execute(Params... params) { return executeOnExecutor(sDefault
  • 全面理解JS(函数)执行顺序

    千次阅读 2018-12-13 23:36:08
     浏览器或者node环境将所有JS检查遍,检查是否有语法错误,注意并不会执行,这里是确保可执行,然后进行第二步:预编译 第二步:预编译 预备知识:变量提升  首先要理解函数声明整体提升,变量 声明提升。...
  • 深入理解JavaScript的执行机制(同步和异步)

    万次阅读 多人点赞 2017-11-24 19:25:59
    深入理解JavaScript执行机制
  • js执行机制深入理解

    万次阅读 2018-11-14 15:35:41
    当 我们像上面这样给个input赋值时,由于onchange时间对input框不起作用,大家首先会想到使用 oninput事件, 然而oninput是需要用户手动输入,先获取焦点改变了值后失去焦点才触发,所以没卵用, 大多数论坛...
  • 理解not exists()——执行过程

    千次阅读 2013-06-20 21:20:25
    众多的SQL语句,not exists()算是难以理解种了。 第次看到,你会觉得有点迷糊,但是似乎还能够理解。但是当你看到下面这样个例子的时候就会谷歌百度之了。 有这样的两个关系: STUDENTS表即学生表,...
  • 本文成于2019年12月25日 ...简单介绍promise Promise是个构造函数,自己身上有all、reject、resolve这几个眼熟的方法,原型上有then、catch等同样很眼熟的方法。 那就new个 var p = new Promise(func...
  • Java HashMap中在resize()时候的rehash,即再哈希法的理解

    万次阅读 多人点赞 2016-08-22 00:24:52
    HashMap的扩容机制---resize() ...当然Java里的数组是无法自动扩容的,方法是使用个新的数组代替已有的容量小的数组,就像我们用个小桶装水,如果想装更多的水,就得换大水桶。 我们分析resi
  • 有时候我们会遇到这样个场景:根据其中个表字段值,判断是否执行其他查询语句。 也就是说,看第个表某字段的“眼色”,由其决定是否进行查询。其实很简单,但容易进入理解误区导致较真儿。 第步:先实现...
  • 面试或工作的过程,也经常会遇到代码执行顺序或函数生命周期加载等类似的问题,这些多多少少都与javascript的执行机制相关。今天发现篇很好的文章,欣喜之余,加以转载,供感兴趣的小伙伴学习,感谢作者分享。...
  • java执行顺序之深入理解clinit和init

    千次阅读 2018-06-05 17:24:54
    前言: 最近研究了深入理解JVM这本书的知识,对java各部分执行的顺序有了比较深入的了解。首先我们得了解一下javainit和clinit的区别。概念: 类型初始化方法&lt;clinit&gt;:JVM通过Classload进行...
  • 记得前面的文章,我带大家一起从源码的角度分析了AndroidView的事件分发机制,相信阅读过的朋友对View的事件分发已经有比较深刻的理解了。 还未阅读过的朋友,请先参考 Android事件分发机制完全解析,带你从...
  • php一句话木马变形技巧

    万次阅读 多人点赞 2019-09-23 21:33:53
    为了绕过waf的检测,一句话木马出现了无数变形,但本质是不变的:木马的函数执行了我们发送的命令。 二、我们如何发送命令,发送的命令如何执行? 我们可以通过 GET、POST、COOKIE这三种方式向一个网站提交数据,...
  • 深入理解Java枚举类型(enum)

    万次阅读 多人点赞 2017-05-13 18:27:14
    【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) ... 出自【zejian的博客】 关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) ...深入理解
  • 理解C++函数的返回

    千次阅读 2013-11-21 11:39:36
    各种书都会详讲返回值的问题,而学生们掌握的难点却是返回至何处执行。本文试图通过对一般函数及递归函数 从程序执行的流程角度,返回即是“被调用函数执行结束后,返回至调用这个函数的位置,接着完成其他任务...
  • Verilog顺序语句的理解

    千次阅读 2017-01-07 17:18:49
    顺序语句是执行一句执行下一句,如果有非阻塞就要按照并行处理,再说几个概念: 并行,顺序:verilog主要的模块之间都是并行执行的,例如各个always之间 如果你一个always要对a赋值,而另一个always要...
  • 个程序的执行过程

    千次阅读 2017-10-22 20:15:56
    源程序,是指未经编译...C语言,.c文件就是所谓的源文件,接下来,我们剖析一下,源程序到可执行程序的过程。这个过程,会发生如下的变化: .c文件生成.obj文件的过程,我们称为编译,.obj文件生成到.exe文
  • 木马学习笔记 1【一句话木马篇】

    千次阅读 2017-10-27 21:35:47
    注意注意:本博客仅供学习交流使用,不可用于任何违法行为,学信息安全,保卫我国信息安全,爱我中国~ ummmm,之前队内交流提到了线下赛的木马,和表哥们的交流...1.最最最最基础一句话 eval($_POST["...
  • PHP一句话木马后门

    千次阅读 2019-01-23 12:16:03
    我们进行渗透测试的最后阶段,入侵到内网里,无论是想要浏览网站结构,还是抓取数据库,或者是挂个木马等等,到最后最常用的就是执行一句话木马,从客户端轻松连接服务器。 一句话木马的原理很简单,造型也很简单...
  • 一般情况,当我们频繁的使用线程的时候,为了节约资源快速响应需求,我们都会考虑使用线程池,线程池...下面我就用一句话来说明白shutdown和shutdownNow的区别。 一、一句话说明白shutdown和shutdownNow的区别 shutd
  • Mac 环境变量的配置和理解

    万次阅读 多人点赞 2017-01-19 18:13:11
    我们先来看这样的个使用场景1,我们有个程序Java,需要读取某个文件(/data/file.txt)。 那么我们运行的时候是不是需要做如下的步骤: cd 到Java的目录执行Java命令; 但是,当我们需要同时使用多个...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 364,387
精华内容 145,754
关键字:

在理解中执行下一句