图片 12

可以响应html表单的Tiny,从零开始学习前端JAVASCRIPT

  最近学习到了《深入理解计算机系统》的第11章网络编程,在最后一节是一个名为Tiny的小型web服务器的实现,源代码书中已经给出,这里就不再复制粘贴了。这篇小博客主要记录一下课后题10的解答。原题目为:
     写出CGI
adder函数的HTML表单。你的表单应该包括两个文本框,用户将需要相加的两个数字填在这两个文本框中。你的表单应该使用GET方法请求内容。
   
 因为我以前没接触过HTML表单,先百度之,找到了w3school的HTML教材,看了一下表单的部分,写出了一个很简单的小表单,命名为index.html:

 

1:BOM(Browser  Object  Model)概念

window对象是BOM中所有对象的核心。 


2:window属性(较少用)

self:self代表自己,相当于window。 

window.self; //指向自身窗口

  parent:返回父窗口。

window.parent //指向父元素的窗口

 

top:返回顶层窗口,和parent作用一样。

 

window.top
console.log(window.parent == window.top);

 

  opener:窗口开启者。

console.log(window.opener);

 3:window方法

1.window.open(url,
name, feature, replace);

window.open('opener.html', 'open');//打开opener.html的页面,窗口的标题open

 

url:一个可选的字符串,声明了要在新窗口中显示的文档的
URL。如果省略了这个参数,或者它的值是空字符串,那么新窗口就不会显示任何文档。

name:一个可选的字符串,该字符串是一个由逗号分隔的特征列表,其中包括数字、字母和下划线,该字符声明了新窗口的名称。

这个名称可以用作标记
<a> 和 <form> 的属性 target 的值。

feature:自行扩展。replace:自行扩展。

谷歌默认会把系统自动打开的新网页阻止掉,但不阻止通过事件打开新的网页。

2.close:关闭浏览器。(window.close()//关闭浏览器窗口)

但都支持通过别的网页打开的新的网页关闭。

3.alert(显示的文本):弹出窗。(window.alert()//浏览器窗口弹框)

4.confirm(对话框提示的文字):该方法有返回值,点击确定返回true,点击取消返回false。 

console.log(window.confirm('今天下雪了吗?')); //点击确认输出true;点击取消输出false

5.prompt(提示信息):输入框。点击确定返回字符串,点击取消返回null。

console.log(window.prompt('请问1+1等于几?'));
//弹出窗口有书写区域,返回值为输入的信息,若不填写为null

 


4:history对象

该对象包含浏览器窗口访问过的url。

1.属性

length 
返回浏览器历史记录的数量

2.方法(使用以下方法返回网页history的记录不增不减)

back()
后退,加载前一个url。

forward()
前进。

go(number) 
如果参数是正数,那么就是前进相应的数目,如果是负数那么反之,如果是0那么就是刷新。

 

图片 1图片 2

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>file1</title>
</head>
<body>
    <a href="file2.html">file2</a>
    <a href="file3.html">file3</a>
    <a href="file4.html">file4</a>
    <button id="back">回退到上一个页面</button>
    <button id="forward">前进到下一个页面</button>
    <button id="go">进两步</button>
    <script>
        console.log(history.length);
        var oBack = document.getElementById('back')
        oBack.onclick = function () {
            history.back()
        }

        var oForward = document.getElementById('forward')
        oForward.onclick = function () {
            history.forward()
        }

        var oGO = document.getElementById('go')
        oGO.onclick = function () {
            history.go(2)
        }
    </script>
</body>
</html>

页面一的代码

  

图片 3图片 4

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>file2</title>
</head>
<body>
    <a href="file1.html">file1</a>
    <a href="file3.html">file3</a>
    <a href="file4.html">file4</a>
    <button id="go">后退1步</button>
    <button id="back">回退到上一个页面</button>
    <button id="forward">前进到下一个页面</button>
    <script>
        console.log(history.length);
        var oBack = document.getElementById('back')
        oBack.onclick = function () {
            history.back()
        }
        var oForward = document.getElementById('forward')
        oForward.onclick = function () {
            history.forward()
        }
        var oGO = document.getElementById('go')
        oGO.onclick = function () {
            history.go(-1)
        }
    </script>
</body>
</html>

页面二的代码

 

图片 5图片 6

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>file3</title>
</head>
<body>
    <a href="file1.html">file1</a>
    <a href="file2.html">file2</a>
    <a href="file4.html">file4</a>
    <button id="go">刷新</button>
    <button id="back">回退到上一个页面</button>
    <button id="forward">前进到下一个页面</button>
    <script>
        console.log(history.length);
        var oBack = document.getElementById('back')
        oBack.onclick = function () {
            history.back()
        }
        var oForward = document.getElementById('forward')
        oForward.onclick = function () {
            history.forward()
        }
        var oGO = document.getElementById('go')
        oGO.onclick = function () {
            history.go(0)
        }
    </script>
</body>
</html>

页面三的代码

 

图片 7图片 8

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>file4</title>
</head>
<body>
    <a href="file1.html">file1</a>
    <a href="file2.html">file2</a>
    <a href="file3.html">file3</a>
    <button id="go">后退1步</button>
    <button id="back">回退到上一个页面</button>
    <button id="forward">前进到下一个页面</button>
    <script>
        console.log(history.length);
        var oBack = document.getElementById('back')
        oBack.onclick = function () {
            history.back()
        }
        var oForward = document.getElementById('forward')
        oForward.onclick = function () {
            history.forward()
        }
        var oGO = document.getElementById('go')
        oGO.onclick = function () {
            history.go(-1)
        }
    </script>
</body>
</html>

页面4的代码

  


 5:location对象

包含有当前url的相关信息,而history对象不能具体反应url的相关信息。

完整的URL组成部分:协议(schema http:// )
端口号(port 80 443)/路径(path)查询字符串(? query)锚点连接(#
hash)

 

属性:

href:设置或返回完整的url。可以为相对路径,也可以为绝对路径。 

search:返回url?后面的查询部分。hash
:是一个可读可写的字符串,该字符串是 URL 的锚部分(从 #
号开始的部分)。

方法:

assign(url):加载新的文档。 

reload(boolean):重新加载文档,当参数是true,任何时候都会重新加载,false的时候,只有在文档改变的时候才会加载,否则直接读取内存当中的。

replace(url):用新的文档代替当前的文档。但不会在
History 对象中生成一个新的记录。当使用该方法时,新的 URL 将覆盖 History
对象中的当前记录。


 6:navigator对象

 1 <!DOCTYPE html>
 2 <html>
 3 <body>
 4 
 5 <p>
 6 please enter two numbers:<br>
 7 </p>
 8 
 9 <form action="/cgi-bin/adder">
10   The first number:
11   <input type="number" name="num1"> <br>
12   The second number:
13   <input type="number" name="num2"> <br>
14   <input type="submit" value="Submit">
15 </form>
16 
17 </body>
18 </html>

本文出处: 

userAgent:用户代理信息,通过该属性可获取浏览器及操作系统信息。可通过此对象查看浏览器的信息,项目的不兼容此版本浏览器可给出用户的相关建议。

console.log(navigator.userAgent);

图片 9


7:window事件

  • onresize:窗口缩放事件。

    window.onresize = function () {
    console.log(2)
    }

  •  onload:加载事件网页加载完毕后执行。//
    获取浏览器视窗宽度/高度

    window.onload = function () {
    console.log(document.documentElement.clientWidth)
    console.log(document.documentElement.clientHeight)
    }

  • onscroll:滚动事件。//
    获取浏览器滚动条隐藏的宽度/高度

chrome(body)、火狐、IE(documentElement)

通过或者的方式兼容各版本的浏览器:

  window.onscroll = function () {
    var iScrollT = document.documentElement.scrollTop || document.body.scrollTop;
    var iScrollL = document.documentElement.scrollLeft || document.body.scrollLeft;
    console.log(iScrollL)
  }

 

  这是输入localhost:8888之后浏览器显示的效果图。8888是我设置的tiny的端口,至于为什么没有后边的/index.html,是因为我在源代码中将index.html设为了主界面。

 

图片 10

 

  我们可以随便输入两个数字,点击Submit按钮,结果肯定是不对的。。

周围又有人在讨论UNION和UNION ALL,对于UNION和UNION
ALL,网上说的最多的就是性能问题(实在不想说出来这句话:UNION
ALL比UNION快)
其实根本不想炒UNION和UNION ALL这碗剩饭了,
每次看到网上说用这个不用那个,列举的一条一条的那种文章,只要看到说UNION
ALL比UNION性能好的就……

图片 11

对于合并的结果集,UNION是去重的,UNION
ALL是不去重的,去重与不去重是两个目的,分别由UNION和UNION ALL实现
两个作用(功能)不同的东西,放一起比性能有什么意义?
这种问题真的是无聊至极,就好比“足球场上的某个中后卫和某个前腰哪个能力更强”一样没有可比性,
他们的作用本身就是不同的,难道说中后卫能力不行,把他撤下来,用一个牛逼的前腰球员替代中后卫,或者是前腰能力不行,撤下他用牛逼的中后卫替代?
这是在功能上的区别,至于性能,我个人认为对比起来没有任何意义。
如果非要放一起比的话,做同样的数据合并,
UNION因为要去重,相对UNION
ALL来说,(相对)当然会耗费更多的资源(耗费的资源多少跟性能无关,做的事情多,当然需要更多的资源)
但是一定要弄清楚,合并数据的时候,到底要不要去掉重复数据,这是最终结果对与错的问题,不是性能问题!

  如上图所示,结果显示的是0。注意在该网页的地址栏处,我们看到”localhost:8888/cgi-bin/adder?num1=22&num2=22″,看过tiny源码我们就会知道,adder.c所要分析的数据是在&符号两边的纯数字,也就是说,要想正确的被adder.c程序求和,地址栏应该显示”localhost:8888/cgi-bin/adder?22&22″才对。出现上图中的错误的原因就是,adder程序没有取得两个参数的数值大小。解决方法很简单,只需要在adder.c程序里把两个数字取出来就行了,整个adder.c代码如下所示:

这里不讨论UNION和UNION ALL的性能了,
从另外一个点入手来发起问题
UNION与UNION
ALL最大的区别就是UNION会去重,那么问题就来了,这个去重是怎么实现的?去重会对查询的默认顺序集产生什么影响?

 1 #include "net.h"
 2 
 3 int main(void)
 4 {
 5     char *buf, *p;
 6     char arg1[MAXLINE], arg2[MAXLINE], content[MAXLINE];
 7     char tmp[MAXLINE];
 8     int n1 = 0, n2 = 0;
 9 
10     if ( (buf = getenv("QUERY_STRING")) != NULL) {
11         p = strchr(buf, '&');
12         *p = '\0';
13 
14         strcpy(arg1, buf);
15         strcpy(arg2, p+1);
16 
17         //用来取出两个参数的代码
18         p = strchr(arg1, '=');
19         strcpy(arg1, p+1);
20         p = strchr(arg2, '=');
21         strcpy(arg2, p+1);
22 
23         n1 = atoi(arg1);
24         n2 = atoi(arg2);
25     }
26 
27     sprintf(content, "QUERY_STRING = %s", buf);
28     sprintf(content, "Welcome to add.com: ");
29     //sprintf(content, "arg1=%s, arg2=%s\n", arg1, arg2);  调试输出参数
30     sprintf(content, "%sThe Internet addition portal.\r\n<p>", content);
31     sprintf(content, "%sThe answer is: %d + %d = %d\r\n<p>",
32             content, n1, n2, n1 + n2);
33     sprintf(content, "%sThanks for visiting!\r\n", content);
34 
35     //generate the http response
36     printf("Connection: close\r\n");
37     printf("Content-length: %d\r\n", (int)strlen(content));
38     printf("Content-type: text/html\r\n\r\n");
39     printf("%s", content);
40     fflush(stdout);
41 
42     exit(0);
43 }

 

  重新编译adder.c之后,我们再次在浏览器输入网址:localhost:8888,输入两个数字,结果如图:

UNION去重的实现

图片 12

测试一下UNION运算符去重的实现原理

  至此,我们学习Tiny的第一阶段就算完成了,完成了课后题11.10的要求,能够处理来自浏览器的静态请求和动态请求。但是,由于我们的Tiny一次只能处理一个连接,效率太低了。下一节我们就要对Tiny进行一下改进,使其能够支持并发处理。

create table TestUnion1
(    

    Id1 INT PRIMARY KEY,
    Id2 tinyint,
    Name varchar(100)
);
create table TestUnion2
(
    Id1 INT PRIMARY KEY,
    Id2 tinyint,
    Name varchar(100)
);

insert into TestUnion1 values (500,9,'aaa')
insert into TestUnion1 values (700,3,'ccc')
insert into TestUnion1 values (200,7,'eee')


insert into TestUnion2 values (300,2,'bbb')
insert into TestUnion2 values (800,8,'ddd')
insert into TestUnion2 values (100,5,'fff')

--TestUnionALL1和TestUnionALL2中相同的数据
insert into TestUnion1 values (600,6,'xxx')
insert into TestUnion2 values (600,6,'xxx')

UNION在去重的过程中,使用的执行计划是Merge Join,UNION
ALL是不去重的,同样步骤对应的执行计划是Concatenation

发表评论

电子邮件地址不会被公开。 必填项已用*标注

标签:
网站地图xml地图