Meathill

Meathill 查看完整档案

广州编辑中国地质大学(武汉)  |  应用化学 编辑OpenResty Inc.  |  高级前端工程师 编辑 blog.meathill.com/ 编辑
编辑

爱编程,爱旅游,爱吐槽。

今年的目标是多做直播和视频,现阶段目标:坚持工作日直播。近期直播内容:

  • JavaScript 设计模式
  • 浏览器扩展开发共享收藏夹
  • 小程序开发卡通照片

欢迎大家到B站找我:https://space.bilibili.com/74...。欢迎广州的小伙伴约线下面基。

个人动态

Meathill 回答了问题 · 4月4日

解决不懂就问,用 setTimeout 简单实现 setInterval 的问题

JS 里的定时器也依赖 event loop,并不是严格按照时间。所以虽然支持你用 ms 设置定时器,但什么时候触发其实不一定。所以建议至少以 10ms 为标准,也不要让不同定时器互相影响。

关注 3 回答 2

Meathill 回答了问题 · 4月2日

vue 计算属性

  1. 这里应该用 method,如果出于缓存数据的考虑,应该对整个数据进行格式化
  2. if (xxx) return true 太……直接 return xxx 就好了

关注 3 回答 2

Meathill 回答了问题 · 4月1日

vue3没有官方对应的dev-tools吗?

  1. 去 v3 的官网 https://v3.vuejs.org/
  2. 在导航里找 'Ecosystem'(生态)
  3. 在里面找到 Devtools https://github.com/vuejs/vue-...
  4. 在 README 里找到教程:https://github.com/vuejs/vue-...

关注 3 回答 2

Meathill 赞了文章 · 3月30日

CPU 提供了什么

为了方便理解,CPU 可以简单认为是:

  1. 一堆的寄存器,用于暂时存放数据
  2. 可以执行机器指令,完成运算 / 数据读写 等操作

寄存器

CPU 有很多的寄存器,这里我们只介绍 指令寄存器 和 通用寄存器。

指令寄存器

64 位下,指令寄存器叫 rip (32 位下叫 eip)。
指令寄存器用于存放下一条指令的地址,CPU 的工作模式,就是从 rip 指向的内存地址取一条指令,然后执行这条指令,同时 rip 指向下一条指令,如此循环,就是 CPU 的基本工作。

也就意味着,通常模式下 CPU 是按照顺序执行指令的。但是,CPU 也有一些特殊的指令,用于直接修改 rip 的地址。比如,jmp 0xff00 指令,就是把 rip 改为 0xff00,让 CPU 接下来执行内存中 0xff00 这个位置的指令。

通用寄存器

以 x86_64 来说,有 16 个“通用”寄存器。“通用”意味着可以放任意的数据,这 16 个寄存器并没有什么区别,但是实际上还是存在一些约定俗称的用法:

先看看这 8 个:
(这是原来 32 位架构下就有的,只是 32 位下是 e 开头的)

rax: "累加器"(accumulator), 很多加法乘法指令的缺省寄存器,函数返回值一般也放在这里
rbx: "基地址"(base)寄存器, 在内存寻址时存放基地址
rcx: 计数器(counter), 是重复(REP)前缀指令和 LOOP 指令的内定计数器
rdx: 用来放整数除法产生的余数,或者读写I/O端口时,用来存放端口号
rsp: 栈顶指针,指向栈的顶部
rbp: 栈底指针,指向栈的底部,通常用`rbp+偏移量`的形式来定位函数存放在栈中的局部变量
rsi: 字符串操作时,用于存放数据源的地址
rdi: 字符串操作时,用于存放目的地址的,和 rsi 经常搭配一起使用,执行字符串的复制等操作

另外还有 8 个,是 64 位架构下新增的:

r8, r9, r10, r11, r12, r13, r14, r15

机器指令

在 CPU 的世界里,只有 0 1 这种二进制的表示,所以指令也是用 0 1 二进制表示的。
然而,二进制对人类并不友好,所以有了汇编这种助记符。

算术运算

比如这段加法:

add    rax,rdx

比如这个汇编指令,表示:rax = rax + rdx,这就完成了一个加法的运算。
通常我们用 rax 寄存器来做加法运算,但是其他寄存器一样也可以完成加法运算的,比如:

add    rbx,0x1

这个表示 rbx = rbx + 0x1

这里的加法运算,都是在寄存器上完成的,也就是直接修改的寄存器的值。

跳转指令

比如这段无条件跳转指令

jmp 0x269e001c

CPU 默认是按照顺序执行指令的,跳转指令则是,让 CPU 不再顺序执行后续的指令,转而执行 0x269e001c 这个内存地址中的指令。
具体来说,将指令寄存器中的值改为 0x269e001c 即可,即:rip = 0x269e001c

内存读写指令

比如这一对 mov 指令:

mov rbp, [rcx]
mov [rcx], rbp

这里假设 rcx 的值,是一个内存地址,比如:0xff00
第一行 mov 指令,是将内存地址 0xff00 中的值,读取到 rbp 寄存器。
第二行 mov 指令,则是反过来,将 rbp 寄存器的值,写入到内存 0xff00 中。

栈操作

pushpop 这一对用于操作“栈”。
“栈”是内存空间中的一段地址,我们约定是以栈的形式来使用它,并且用 rsp 寄存器指向栈顶。

栈操作本质也是内存读写操作,只是以栈的方式来使用。

比如这一对:

push   rbp
pop    rbp

第一行是将 rbp 寄存器中的值压入栈,等效于:

sub rsp, 8       // rsp = rsp - 8; 栈顶向下生长 8 byte
mov [rsp], rbp   // rbp 的值写入新的栈顶

第二行则是反过来,栈顶弹出一个值,写入到 rbp 寄存器中,等效于:

mov rbp, [rsp]   // 栈顶的值写入 rbp
add rsp, 8       // rsp = rsp + 8; 栈顶向上缩小 8 byte

注意:因为栈在内存空间中是倒过来的,所以是向下生长的。

查看原文

赞 11 收藏 2 评论 0

Meathill 关注了用户 · 3月30日

doujiang24 @doujiang24

中年程序员

关注 413

Meathill 回答了问题 · 3月28日

git分支修改合并问题

  1. main 是主干,是发布的基础
  2. dev1 合并到 main,就应该删掉 dev1
  3. dev2 合并到 main,也应该删掉 dev2
  4. 将来有需要,再开分支
  5. dev2 不应该修改 dev1,每个分支只应该干自己的事情

关注 3 回答 2

Meathill 回答了问题 · 3月27日

Git子仓库如何操作?

git submodule 可以维护子仓库。不过根据我多年实践,子仓库并不好用,维护性和易用性都不如依赖管理,比如 node.js 下的 NPM。

关注 4 回答 3

Meathill 收藏了文章 · 3月27日

resty 命令行工具演示

https://www.bilibili.com/vide...

在本教程中,我们将演示如何使用 OpenResty 附带的 resty 命令行工具。

cd ~
export PATH=/usr/local/openresty/bin:$PATH
which resty

截图 1

一般都是这个路径。

我们可以通过 -V 选项检查其版本号。

resty -V

截图 3

如果你使用我们预构建的 Linux 二进制包安装 OpenResty,那么你应该安装 openresty-resty 包。

dnf list installed openresty-resty

截图 4

因为它不在 openresty 主包中。

比如用 resty 命令来做“hello world”,就容易多了。

resty -e 'print("Hello World")'

截图 6

注意 -e 选项。

或者在终端上运行一个 Lua 脚本。

echo 'print("Hello World")' > hello.lua
cat hello.lua
resty hello.lua

截图 8

所以这也是使用 OpenResty 编写新的命令行应用程序的好方法。

这里也可以实现非阻塞 I/O。

time resty -e 'ngx.sleep(1) ngx.say("done")'

截图 10

让我们使用 cosocket API 连接到 openresty.com 的 443 端口。

resty -e 'local sock = ngx.socket.tcp() print(sock:connect("openresty.com", 443))'

截图 11

或者使用轻线程。

resty -e 'ngx.thread.wait(ngx.thread.spawn(function () print("in thread!") end))'

截图 12

你也可以很容易地使用 Lua 模块。让我们创建一个 test 模块。

mkdir lua/
vim lua/test.lua

lua/test.lua文件是这样的。

local _M = {}

function _M.hello() print("Hello") end

return _M

截图 13

然后我们使用 -I 选项将 lua/ 目录添加到 Lua 模块搜索路径中。

resty -I lua/ -e 'require "test".hello()'

截图 14

如果没有 -I 选项,它就找不到。

resty -e 'require "test".hello()'

截图 15

这是因为 lua/ 目录默认不在 Lua 模块的搜索路径中。

可以直接加载标准的 Lua 模块,比如 resty.shell

resty -e 'local ok, stdout = require "resty.shell".run([[echo ok]]) print(stdout)'

截图 17

该模块用于非阻塞地运行少量 shell 命令。

我们也可以通过 --shdict 选项来定义 lua 共享内存字典。

resty --shdict 'dogs 10m' -e 'print(ngx.shared.dogs:set("age", 11))'

截图 19

可以这样定义多个共享词典。

resty --shdict 'dogs 7m' --shdict 'cats 5m' -e 'print(ngx.shared.dogs, " ", ngx.shared.cats)'

截图 20

它还可以方便地注入自定义的 nginx 配置代码。

resty --http-conf 'lua_regex_match_limit 102400;' -e 'print "ok"'

截图 21

我们还可以玩玩 LuaJIT 的 JIT 编译器。

让我们创建一个跑得比较热的 Lua 脚本。

echo 'local a = 0 for i = 1, 1e8 do a = a + 1 end print(a)' > bench.lua
cat bench.lua

截图 23

然后完全禁用 JIT 编译器。

time resty -joff bench.lua

截图 24

为了比较,我们可以检查一下启用 JIT 编译器后速度有多快。

time resty bench.lua

截图 25

或者我们可以用 -jv 选项检查编译后的 Lua 代码路径,或者说“traces”。

resty -jv bench.lua

截图 26

或者有更多的细节,比如编译后的字节码转储,IR 代码转储,以及机器代码转储。

resty -jdump bench.lua

你可以随时通过 -h 选项找到所有支持的功能。

resty -h

或者通过“restydoc”工具参考其文档。

restydoc resty-cli

如果你通过我们预建的二进制包安装 openresty,那么你应该安装 openresty-docopenresty-restydoc 包。

dnf list installed openresty-doc

截图 30

我们将在另一个专门的视频教程中更深入地了解“restydoc”工具。
如果你喜欢这个教程,请订阅这个博客网站和我们的 YouTube 频道B 站频道。谢谢!

<!-- xray "通过 OpenResty XRay 产品提升您应用的性能" -->

关于本文和关联视频

本文和相关联的视频都是完全由我们的 OpenResty Demo 系统从一个极简单的剧本文件自动生成的。

关于作者

章亦春是开源项目 OpenResty® 的创始人,同时也是 OpenResty Inc. 公司的创始人和 CEO。他贡献了许多 Nginx 的第三方模块,相当多 Nginx 和 LuaJIT 核心补丁,并且设计了 OpenResty XRay 等产品。

关注我们

如果您喜欢本文,欢迎关注我们 OpenResty Inc. 公司的博客网站 。也欢迎扫码关注我们的微信公众号:

我们的微信公众号

翻译

我们提供了英文版原文和中译版(本文) 。我们也欢迎读者提供其他语言的翻译版本,只要是全文翻译不带省略,我们都将会考虑采用,非常感谢!

查看原文

Meathill 赞了文章 · 3月27日

resty 命令行工具演示

https://www.bilibili.com/vide...

在本教程中,我们将演示如何使用 OpenResty 附带的 resty 命令行工具。

cd ~
export PATH=/usr/local/openresty/bin:$PATH
which resty

截图 1

一般都是这个路径。

我们可以通过 -V 选项检查其版本号。

resty -V

截图 3

如果你使用我们预构建的 Linux 二进制包安装 OpenResty,那么你应该安装 openresty-resty 包。

dnf list installed openresty-resty

截图 4

因为它不在 openresty 主包中。

比如用 resty 命令来做“hello world”,就容易多了。

resty -e 'print("Hello World")'

截图 6

注意 -e 选项。

或者在终端上运行一个 Lua 脚本。

echo 'print("Hello World")' > hello.lua
cat hello.lua
resty hello.lua

截图 8

所以这也是使用 OpenResty 编写新的命令行应用程序的好方法。

这里也可以实现非阻塞 I/O。

time resty -e 'ngx.sleep(1) ngx.say("done")'

截图 10

让我们使用 cosocket API 连接到 openresty.com 的 443 端口。

resty -e 'local sock = ngx.socket.tcp() print(sock:connect("openresty.com", 443))'

截图 11

或者使用轻线程。

resty -e 'ngx.thread.wait(ngx.thread.spawn(function () print("in thread!") end))'

截图 12

你也可以很容易地使用 Lua 模块。让我们创建一个 test 模块。

mkdir lua/
vim lua/test.lua

lua/test.lua文件是这样的。

local _M = {}

function _M.hello() print("Hello") end

return _M

截图 13

然后我们使用 -I 选项将 lua/ 目录添加到 Lua 模块搜索路径中。

resty -I lua/ -e 'require "test".hello()'

截图 14

如果没有 -I 选项,它就找不到。

resty -e 'require "test".hello()'

截图 15

这是因为 lua/ 目录默认不在 Lua 模块的搜索路径中。

可以直接加载标准的 Lua 模块,比如 resty.shell

resty -e 'local ok, stdout = require "resty.shell".run([[echo ok]]) print(stdout)'

截图 17

该模块用于非阻塞地运行少量 shell 命令。

我们也可以通过 --shdict 选项来定义 lua 共享内存字典。

resty --shdict 'dogs 10m' -e 'print(ngx.shared.dogs:set("age", 11))'

截图 19

可以这样定义多个共享词典。

resty --shdict 'dogs 7m' --shdict 'cats 5m' -e 'print(ngx.shared.dogs, " ", ngx.shared.cats)'

截图 20

它还可以方便地注入自定义的 nginx 配置代码。

resty --http-conf 'lua_regex_match_limit 102400;' -e 'print "ok"'

截图 21

我们还可以玩玩 LuaJIT 的 JIT 编译器。

让我们创建一个跑得比较热的 Lua 脚本。

echo 'local a = 0 for i = 1, 1e8 do a = a + 1 end print(a)' > bench.lua
cat bench.lua

截图 23

然后完全禁用 JIT 编译器。

time resty -joff bench.lua

截图 24

为了比较,我们可以检查一下启用 JIT 编译器后速度有多快。

time resty bench.lua

截图 25

或者我们可以用 -jv 选项检查编译后的 Lua 代码路径,或者说“traces”。

resty -jv bench.lua

截图 26

或者有更多的细节,比如编译后的字节码转储,IR 代码转储,以及机器代码转储。

resty -jdump bench.lua

你可以随时通过 -h 选项找到所有支持的功能。

resty -h

或者通过“restydoc”工具参考其文档。

restydoc resty-cli

如果你通过我们预建的二进制包安装 openresty,那么你应该安装 openresty-docopenresty-restydoc 包。

dnf list installed openresty-doc

截图 30

我们将在另一个专门的视频教程中更深入地了解“restydoc”工具。
如果你喜欢这个教程,请订阅这个博客网站和我们的 YouTube 频道B 站频道。谢谢!

<!-- xray "通过 OpenResty XRay 产品提升您应用的性能" -->

关于本文和关联视频

本文和相关联的视频都是完全由我们的 OpenResty Demo 系统从一个极简单的剧本文件自动生成的。

关于作者

章亦春是开源项目 OpenResty® 的创始人,同时也是 OpenResty Inc. 公司的创始人和 CEO。他贡献了许多 Nginx 的第三方模块,相当多 Nginx 和 LuaJIT 核心补丁,并且设计了 OpenResty XRay 等产品。

关注我们

如果您喜欢本文,欢迎关注我们 OpenResty Inc. 公司的博客网站 。也欢迎扫码关注我们的微信公众号:

我们的微信公众号

翻译

我们提供了英文版原文和中译版(本文) 。我们也欢迎读者提供其他语言的翻译版本,只要是全文翻译不带省略,我们都将会考虑采用,非常感谢!

查看原文

赞 1 收藏 1 评论 0

Meathill 回答了问题 · 3月26日

解决关于js自执行函数的问题?

不能。(紫薯布丁)

关注 4 回答 3

认证与成就

  • SegmentFault 讲师
  • 获得 892 次点赞
  • 获得 24 枚徽章 获得 3 枚金徽章, 获得 11 枚银徽章, 获得 10 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

  • Meart

    Meart 是一款免费的静态网站生成工具,主要面向摄影师和设计师,帮助他们快速建立个人作品网站。Meart 可以使用各种纯 HTML 的模板,几乎可以生成任何形式的页面。它还附带 HTML 编辑功能,可以使用别的网页作为模板,很轻松的修改成自己希望的样子。 接下来,我还会为 Meart 引入插件体系,提供包括购物在内的一系列功能。 Meart 利用 Electron 基础发布成桌面软件,并且可以快速扩展到服务器端,提供线上服务。

  • JavaScript 异步开发全攻略

    这是一本介绍 JS 异步开发的小书,主要包含 Promise 和 Async,特意介绍了在多个开发场景下的应用。并且保持不断更新。最近更新了在 Vuex 的 action 里返回 Promise 的用法。

注册于 2012-09-03
个人主页被 20.8k 人浏览