整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

Nginx的rewrite之set指令

指令用来设置一个新的变量。

语法 set $variable value;

它可以设置在 server、location、if的位置当中

具体配置案例实例:

设置一个监听端口8081

配置了$name和$age和default_type可以直接将返回值返回到页面当中

检验语法,重新加载

访问81下的server接口,正好输出了Tom=18的内容

variable:变量的名称,该变量名称要用"$"作为变量的第一个字符,且不 能与Nginx服务器预设的全局变量同名。

value:变量的值,可以是字符串、其他变量或者变量的组合等。

Rewrite常用全局变量

1、$args

变量中存放了请求URL中的请求指令。比如htt p://192.168.200.133:8080?arg1=value1&arg s2=value2中 的"arg1=value1&arg2=value2",功能和 $query_string一样

$ages的实际使用,在Ngnix当中添加$ages之后

检验语法,重载配置

$args啥也没有输出,

在端口后添加?sername=JERPY之后,再使用$args之后就输出了参数了,其中$args的意思与$query_string一样

常见的全局变量2

$http_user_agent

变量存储的是用户访问服务的代理信息(如果 通过浏览器访问,记录的是浏览器的相关版本 信息)

什么是代理信息,代理信息是用一些工具访问,如postman,浏览器等

配置实例:在conf文件中添加$http_user_agent;参数

检验语法,重新加载

$http_user_agent输出所打印的内容与浏览器中Network中的User-Agent打印的内容相同

常见的全局参数之$host

变量存储的是访问服务器的server_name值

实际配置,在Ngnix中配置$host文件

检验语法,重新加载

$host输出的内容正好是存储Ngnix的公网IP

常见的全局参数之$document_uri

它代表的是location后面的内容,输出也是ngnix中conf配置文件内容中location下面的内容

常见全局参数之$document_root

变量存储的是当前请求对应location的root 值,如果未设置,默认指向Nginx自带html目 录所在位置

之后检验语法,重新加载

最后可以看到,它输出了root下面的文件内容

也可以在日志文件中使用,log_format中设置的main一定要与access_log的main内容相同才可以

之后找到tail -f ../logs/access.log文件

相应的参数打印出来了

开发功能“轨迹播放”时,遇到了一个情况。
原先同事已经开发了一版,这次有个新功能:点击线上任意一点后可以从点击处重新播放。
看了一下原来的版本,发现同时使用了setTimeout和setInterval,两者配合实现点线播放。
简单结构如下

 function test() {
 setInterval(function () {
 console.log("interval");
 //省略插值方法得到arr
 (...)
 play(arr);
 }, 2000);
 }
 function play(arr) {
 setTimeout(function () {
 play(arr);
 console.log("setTimeout");
 }, 40);
 }

我觉得这个结构欠妥,两个定时器配合必定会出现失误!因此重构了一版,将两个定时器改为一个,用setInterval解决。
但是此时我并不知道欠妥欠在什么地方,缺乏理论支持,现在闲下来仔细研究了一下

0|1找问题

在仔细研究了旧版本后,我先把旧版本结构扒了出来,排除其他因素,自己模拟了一个简单版(就是上面的代码)
setTimeout:在执行时,是在载入后延迟指定时间后,去执行一次表达式,仅执行一次
setInterval:在执行时,它从载入后,每隔指定的时间就执行一次表达式

  • 实验一:在使用setInterval和setTimeout方法上,并没有什么问题,决定跑一下,结果如下

从结果得出两点结论

  1. setTimeout与setInterval并不是50倍速度配合运行着
  2. 两次interval间,timeout运行的次数越来越多,表明setInterval运行间隔越来越长,延迟越来越大
  • 实验二:加一点人工干预再执行
 function test() {
 setInterval(function () {
 console.log("interval");
 play();
 }, 2000);
 }
 function play() {
 //延迟执行
 for (var i = 0; i < 100000000; i++) {
 
 }
 setTimeout(function () {
 play();
 console.log("setTimeout");
 }, 40);
 }

从结果得出两点结论

  1. setInterval可能会随函数处理时间,减少间隔
  2. 推测,因为Javascript是单线程的,setInterval和setTimeout是放队列里执行的,很容易受到回调事件影响
  • 实验三:拖动缩放浏览器

从结果得出结论

  1. 当浏览器标签切换到其他页面,或者浏览器最小化,会影响计时器,两者会出现间隔减小

0|1涉及知识点

综上实验结果,网上搜集了一些资料能说明问题:

  1. JavaScript是单线程,但是浏览器是多线程,Javascript是浏览器多线程中的一个线程。(图参考自:https://www.cnblogs.com/tesky0125/p/4619549.html)

  1. Javascript会把执行的回调函数、浏览器的触发事件、UI渲染事件,先放到队列中,队列根据先进先出的规则,依次执行他们,当执行到队列中的setInterval时很难保证其与setTimeout同步关系还保持。
  2. setInterval无视代码错误:代码报错,但是setInterval依旧会按时执行,不会中断。
  3. setInterval无视网络延迟:如果调用ajax或其他服务,他不会管是否返回回调,会继续按时执行。
  4. setInterval不保证执行:因为setInterval会定时执行,如果函数逻辑很长,间隔时间内执行不完,后续方法会被抛弃。
  5. 会受浏览器状态影响,tab切换、最小化等

0|1解决方案

在做轨迹播放时,setInterval的延迟还在可接受范围之内,但是网上给出的最佳解决方案是用setTimeout做。
setTimeout只会执行一次,在执行完成后,重新启动新的Timeout,时间runtime计算设置为差时,减少出现间隔越来越大的情况


如果写过js代码的人对于setTimeout方法一定不会感到陌生。setTimeout是一种定时器,在前端开发中有很多的应用场景,比如在购物车结算成功后,等待几秒会自动跳转至列表页。今天我们就深入的看下setTimeout的实现原理。

Javascript之setTimeout

基本用法

根据W3C的标准解释,setTimeout是定义一个在指定时间后触发的函数。

我们先来看看setTimeout的基本用法,实现这样一个简单的效果,点击一个button,在3秒后页面上的文字消失。

setTimeout基本用法

由于这段代码非常基础,这里不做过多讲述。

setTimeout(fn, 0)

上面一部分说到setTimeout是相当于给函数定义一个‘闹钟’,当到了指定的时间后就会自动执行函数。但是如果我们将时间设置为0,即出现setTimeout(fn, 0)这样的代码,情况是怎么样的呢?是会立即执行吗?

我们可以通过以下一段代码来进行测试。

测试代码

如果和我们猜测的一样,立即执行的话,上面的测试代码会按照1 > 2 > 3的顺序输出,但是实际运行后,我们发现输出结果的顺序为1 > 3 > 2,而且不管运行多少次结果都不变。

出现了这样的结果,就证明了setTimeout(0)并不是立即执行的,那这又该怎么解释呢?

JS单线程执行

为了解释上面这个问题,我们要追溯到JS执行过程,我们都知道JS是单线程执行,所有的异步事件,包括自定义的页面DOM事件,定时器,Ajax请求都会被添加到一个任务列表按照顺序执行。

因为JS脚本文件是运行在浏览器端的,我们的JS引擎虽然是单线程的,但是对于浏览器来说确是多线程的。浏览器中不仅包括JS引擎,还包括网络请求Ajax,浏览器渲染等,它们都有特定的线程去执行。

setTimeout并不能作为多线程使用,可以通过以下一段代码来证明。

测试代码

对于以上一段代码,如果setTimeout可以作为多线程使用,则新的线程会在一秒后将isEnd属性设置false,那么在一秒后会alert出end字符串。

但是实际情况确是,页面从未打印出end字符串,而且页面会呈现锁死状态,这是因为isEnd变量值并未修改为false,相当于执行while(true),最终页面会崩溃。这也就能证明JS引擎是单线程执行状态。

事件队列

既然JS引擎是单线程执行,那么setTimeout定义的事件该具体何时触发呢?

这里我们需要深入到浏览器内核设计,在内核中涉及到一个事件队列的概念,我们可以直接看如下这张图。

事件队列

从上面这张图很容易看出,在浏览器内核中包含了各式各样的线程,有浏览器GUI渲染线程,Javascript引擎线程,网络请求线程。

在当JS引擎执行到其他线程相关的代码时,就会执行其他线程的代码,在其他线程执行完毕后需要JS引擎重新运行时,就会在JS引擎的事件队列里添加一个任务。

现在我们来看看setTimeout(0)做了什么?它会开启一个定时器线程,并不会影响后续的代码执行,这个定时器线程会在事件队列后面添加一个任务,例如上面图中的t3。等到前面的t1,t2执行完后再去执行t3,因此在前面第二部分内容中的输出顺序为1 > 3 > 2。

setInterval

既然说到了setTimeout,就不得不提到setInterval,setInterval同样作为一种定时器,是在指定的时间间隔后执行相应的函数。

一种最常见的场景是页面上的倒计时实现。这里我们实现一个简单的效果,指定一个时间,并进行倒计时。

倒计时

对比

setTimeout与setInterval虽然都是定时器,但是在执行上还是有不一样的。

  1. setTimeout是指定的时间后执行一次;setInterval是在每隔指定的时间后执行多次。

  2. setTimeout(fn1, t1),fn1的执行时间是大于或等于t1的;setInterval(fn2, t2),fn2的执行会始终尝试在t2时间后执行,如果网络请求较大的话,会出现fn2连续执行的情况。

总结

今天这篇文章主要讲解了Javascript中的setTimeout用法和执行原理,以及与setInterval的简单比较,大家学会了吗?