2022-09-28业务场景00

package.json

npm 离不开 package.json ,要了解 npm 的运行机制,我们先看看 package.json 文件是做什么的。首先 package.json 文件是每个前端项目存在于根目录的文件,包含了项目的一些基本信息(例如项目名称,版本号,描述,一些脚本,依赖等等),大致的结构如下:

{
  "name": "whyknown",
  "version": "1.0.0",
  "description": "whyknown,前端开发者必备网站",
  "main": "src/index.js",
  "scripts": {
    "start": "node index.js",
    "lint": "eslint **/*.js"
  },
  "dependencies": {
    "express": "^4.16.4",
    "compression": "~1.7.4"
  },
  "devDependencies": {
    "eslint": "^5.16.0",
    "nodemon": "^1.18.11"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/xxx.git"
  },
  "author": "whyknown",
  "contributors": [
    {
      "name": "whyknown",
      "email": "example@example.com",
      "url": "https://www.whyknown.com"
    }
  ],
  "keywords": ["server", "osiolabs", "express", "compression"]
}

我们这里重点关注 script 的配置,该配置罗列了一些可以运行的脚本,当我们在根目录执行 npm run 或者 yarn run 的时候,就会去调用这里的命令。我们拿上面的 start 命令来讲解。

2022-09-28JavaScript00

compose

compose 是函数式编程中一个非常重要的函数,compose 的函数作用就是组合函数的,将函数串联起来执行。将多个函数组合起来,一个函数的输出结果是另一个函数的输入参数,一旦第一个函数开始执行,就会像多米诺骨牌一样推导执行了。

2.1 简单例子

比如有这样的需求,输入一个名字 yideng,然后全部变成大写,打印输出 HELLO YIDENG,我们可以考虑用函数组合的方法来解决这个问题,需要两个函数 greeting、toUpper

const greeting = (name) => `hello ${name}`;
const toUpper = (str) => str.toUpperCase();
const fn = compose(toUpper, greeting);
console.log(fn("yideng"));
// HELLO YIDENG

这就是 compose 的大致使用,主要有以下几点:

  • compose 参数是函数,返回也是一个函数
  • 除了第一个函数接受参数,其它函数接受的都是上一个函数的返回值,所以初始函数的参数是多元的,而其它函数的接受值是一元的。
  • compose 函数可以接受任意的参数,所有的参数都是函数,且执行方向是自右向左的,初始函数一定放到参数的最右面。
2022-09-28业务场景00

参考实现

  • 方式一:border-radius
<style>
  #circle {
    background: red;
    width: 100px;
    height: 100px;
    border-radius: 50%;
  }
</style>
<div id="circle"></div>
<script>
  document.querySelector("#circle").onclick = function () {
    alert("ok");
  };
</script>
  • 方式二:map + area

    • map 标签用来定义一个客户端图像映射(带有可点击区域的一副图像);
    • area 标签用来定义图像映射中的区域,area 元素永远嵌套在 map 元素内部;
<img src="xxxxx.png" usemap="#Map" />
<map name="Map" id="Map">
  <area
    shape="circle"
    coords="100,100,50"
    href="https://www.yidengxuetang.com/"
    rel="external nofollow"
    target="_blank"
  />
</map>

area 属性

  • shape:表示热点区域的形状,支持 rect(矩形),circle(圆形),poly(多边形)
  • coords:表示热点区域的坐标,(0,0)表示图片左上角。rect 四个值分别表示左上角坐标和右下角坐标。circle 三个值分别表示圆心坐标和半径。poly 有若干个值,每两个表示一个坐标点。
  • href:表示链接到某个地址,和<a>标签差不多
  • alt:对该区域描述,类似于<img>的 alt
2022-09-28计算机网络00

一、http 协议的队首阻塞

队首阻塞,队首的事情没有处理完的时候,后面的都要等着。

1.1 HTTP1.0 的队首阻塞

对于同一个 tcp 连接,所有的 http1.0 请求放入队列中,只有前一个请求的响应收到了,然后才能发送下一个请求。http1.0 的队首组塞发生在客户端。

1.2 HTTP1.1 的队首阻塞

HTTP1.1 版本上使用了一种 Pipelining 管道技术来并行发送和处理多个请求。让客户端能够并行发送多个请求,服务器端也可以并行处理多个来自客户端的请求。在一个 TCP 连接中,发送多个 HTTP 请求,不需要等待服务器端对前一个请求的响应之后,再发送下一个请求。但是使用了管道技术的 HTTP/1.1,根据 HTTP/1.1 的规则,服务器端在响应时,要严格按照接收请求的顺序发送,即先接收到的请求,需要先发送其响应,客户端浏览器也是如此,接收响应的顺序要按照自己发送请求的顺序来。这样造成的问题是,如果 最先收到的请求的处理时间长的话,响应生成也慢,就会阻塞已经生成了的响应的发送。也会造成队首阻塞。

总的来说,管道技术允许客户端和服务器端并行发送多个请求和响应,但是客户端接收响应的顺序要和自己发送请求的顺序对应,服务器端发送响应的顺序要和自己接收到的请求的顺序对应,这样做似乎没什么问题,看起来是不是“FIFO”先来先服务的方式,如果前面收到的一个请求,在服务器端处理的时间很长,生成响应需要很多时间,那么对于后面的已经处理完生成响应的请求来说,它们只能阻塞等待,等待前面的响应发送完后,自己才能被发送出去(即使该请求的响应已经生成),造成了“队首阻塞”问题。可见队首阻塞发生在服务器端,虽然服务器端并行接收了多个请求,也并行处理生成多个响应,但由于要遵守 HTTP/1.1 的规则,先接收到的请求需要先发送响应,造成了阻塞问题。

另外需要注意的是,虽然 HTTP/1.1 规范中规定了 Pipelining 管道技术来并行发送和处理多个请求,但是这个功能在浏览器中默认是关闭的。

看一下 Pipelining 是什么,RFC 2616 中的规定 A client that supports persistent connections MAY "pipeline" its requests (i.e., send multiple requests without waiting for each response). A server MUST send its responses to those requests in the same order that the requests were received. 一个支持持久连接的客户端可以在一个连接中发送多个请求(不需要等待任意请求的响应)。收到请求的服务器必须按照请求收到的顺序发送响应。 至于标准为什么这么设定,我们可以大概推测一个原因:由于 HTTP/1.1 是个文本协议,同时返回的内容也并不能区分对应于哪个发送的请求,所以顺序必须维持一致。比如你向服务器发送了两个请求 GET /query?q=A 和 GET /query?q=B,服务器返回了两个结果,浏览器是没有办法根据响应结果来判断响应对应于哪一个请求的。

Pipelining 这种设想看起来比较美好,但是在实践中会出现许多问题:

  • 一些代理服务器不能正确的处理 HTTP Pipelining。
  • 正确的流水线实现是复杂的
  • Head-of-line Blocking 连接头阻塞:在建立起一个 TCP 连接之后,假设客户端在这个连接连续向服务器发送了几个请求。按照标准,服务器应该按照收到请求的顺序返回结果,假设服务器在处理首个请求时花费了大量时间,那么后面所有的请求都需要等着首个请求结束才能响应。

所以现代浏览器默认是不开启 HTTP Pipelining 的。

2022-09-28JavaScript00

let

块级作用域 重复声明

function outputNum(count){
//块级作用域
  (function(){
    for(var i = 0; i < count; i ++){
      console.log(i)
    }
  })()
  console.log(i)
}
outputNum(5)

const

function _const(key, value) {
	window[key] = value
	Object.defineProperty(window, key, {
		enumerable: false,
		configurable: false,
		get: function () {
			return value
		},
		set: function(newValue) {
			if (newValue !== value) {
				throw TypeError('这是只读变量,不可修改')
			} else {
				return value
			}
		}
	})
}