linux常用命令英文含义

linux命令

linux系统,基于GPL开源,很伟大,以至于在计算机世界无处不在,我们已经离不开它了。现在的系统,基本上都有两种方式提供给用户获取系统资源的能力,一种是图形界面,一种就是命令行。作为用户,大多数人使用图形界面,因为它相对于命令行,交互性简直不要太好。但是对于开发人员,有时候命令行的效率可能更高,虽然这些命令很枯燥,很不好记,特别是linux的一些缩写,英语不太好的,表示咋看之下很难懂它的含义,以至于记不住,这里不知道大家的记忆方法是什么,我是那种靠理解记忆的,不懂含义,即使一个字母,在一句命令中,也是很难记住的。真实痛苦啊。。。

搜罗的常用linux命令含义

so, 只能去搜罗那些含义啦,幸好找到了不少,现在据为己有,哈哈。

ls:list(列出目录内容)

cd:Change Directory(改变目录)

su:switch user 切换用户

rpm:redhat package manager 红帽子打包管理器

pwd:print work directory 打印当前目录 显示出当前工作目录的绝对路径

ps: process status(进程状态,类似于windows的任务管理器) 常用参数:-auxf

ps -auxf 显示进程状态

df: disk free 其功能是显示磁盘可用空间数目信息及空间结点信息。换句话说,就是报告在任何安装的设备或目录中,还剩多少自由的空间。

rpm: 即RedHat Package Management,是RedHat的发明之一

rmdir:Remove Directory(删除目录)

rm:Remove(删除目录或文件)

cat: concatenate连锁 cat file1 file2>>file3把文件1和文件2的内容联合起来放到file3中

insmod: install module,载入模块

ln -s : link -soft 创建一个软链接,相当于创建一个快捷方式

mkdir:Make Directory(创建目录

touch

man: Manual

pwd:Print working directory

su:Swith user

cd:Change directory

ls:List files

ps:Process Status

mkdir:Make directory

rmdir:Remove directory

mkfs: Make file system

fsck:File system check

cat: Concatenate

uname: Unix name

df: Disk free

du: Disk usage

lsmod: List modules

mv: Move file

rm: Remove file

cp: Copy file

ln: Link files

fg: Foreground

bg: Background

chown: Change owner

chgrp: Change group

chmod: Change mode

umount: Unmount

dd: 本来应根据其功能描述“Convert an copy”命名为“cc”,但“cc”已经被用以代表“C Complier”,所以命名为“dd”

tar:Tape archive

ldd:List dynamic dependencies

insmod:Install module

rmmod:Remove module

lsmod:List module

文件结尾的”rc”(如.bashrc、.xinitrc等):Resource configuration

Knnxxx / Snnxxx(位于rcx.d目录下):K(Kill);S(Service);nn(执行顺序号);xxx(服务标识)

.a(扩展名a):Archive,static library

.so(扩展名so):Shared object,dynamically linked library

.o(扩展名o):Object file,complied result of C/C++ source file

RPM:Red hat package manager

dpkg:Debian package manager

apt:Advanced package tool(Debian或基于Debian的发行版中提供)

部分Linux命令缩

bin = BINaries #下面的是一些二进制程序文件

/dev = DEVices #下面的是一些硬件驱动

/etc = ETCetera #目录存放着各种系统配置文件, 类似于windows下的system

/lib = LIBrary

/proc = PROCesses

/sbin = Superuser BINaries

/tmp = TeMPorary

/usr = Unix Shared Resources

/var = VARiable ?

/boot=boot #下面的是开机启动文件

FIFO = First In, First Out

GRUB = GRand Unified Bootloader

IFS = Internal Field Seperators

LILO = LInux LOader

MySQL = My是最初作者女儿的名字,SQL = Structured Query Language

PHP = Personal Home Page Tools = PHP Hypertext Preprocessor

PS = Prompt String

Perl = “Pratical Extraction and Report Language” = “Pathologically Eclectic Rubbish Lister”

Python 得名于电视剧Monty Python’s Flying Circus

Tcl = Tool Command Language

Tk = ToolKit

VT = Video Terminal

YaST = Yet Another Setup Tool

apache = “a patchy” server

apt = Advanced Packaging Tool

ar = archiver

as = assembler

awk = “Aho Weiberger and Kernighan” 三个作者的姓的第一个字母

bash = Bourne Again SHell

bc = Basic (Better) Calculator

bg = BackGround

biff = 作者Heidi Stettner在U.C.Berkely养的一条狗,喜欢对邮递员汪汪叫。

cal = CALendar

cat = CATenate

cd = Change Directory

chgrp = CHange GRouP

chmod = CHange MODe

chown = CHange OWNer

chsh = CHange SHell

cmp = compare

cobra = Common Object Request Broker Architecture

comm = common

cp = CoPy

cpio = CoPy In and Out

cpp = C Pre Processor

cron = Chronos 希腊文时间

cups = Common Unix Printing System

cvs = Current Version System

daemon = Disk And Execution MONitor

dc = Desk Calculator

dd = Disk Dump

df = Disk Free

diff = DIFFerence

dmesg = diagnostic message

du = Disk Usage

ed = editor

egrep = Extended GREP

elf = Extensible Linking Format

elm = ELectronic Mail

emacs = Editor MACroS

eval = EVALuate

ex = EXtended

exec = EXECute

fd = file descriptors

fg = ForeGround

fgrep = Fixed GREP

fmt = format

fsck = File System ChecK

fstab = FileSystem TABle

fvwm = F*** Virtual Window Manager

gawk = GNU AWK

gpg = GNU Privacy Guard

groff = GNU troff

hal = Hardware Abstraction Layer

joe = Joe’s Own Editor

ksh = Korn SHell

lame = Lame Ain’t an MP3 Encoder

lex = LEXical analyser

lisp = LISt Processing = Lots of Irritating Superfluous Parentheses

ln = LiNk

lpr = Line PRint

ls = list

lsof = LiSt Open Files

m4 = Macro processor Version 4

man = MANual pages

mawk = Mike Brennan’s AWK

mc = Midnight Commander

mkfs = MaKe FileSystem

mknod = MaKe NODe

motd = Message of The Day

mozilla = MOsaic GodZILLa

mtab = Mount TABle

mv = MoVe

nano = Nano’s ANOther editor

nawk = New AWK

nl = Number of Lines

nm = names

nohup = No HangUP

nroff = New ROFF

od = Octal Dump

passwd = PASSWorD

pg = pager

pico = PIne’s message COmposition editor

pine = “Program for Internet News & Email” = “Pine is not Elm”

ping = 拟声 又 = Packet InterNet Grouper

pirntcap = PRINTer CAPability

popd = POP Directory

pr = pre

printf = PRINT Formatted

ps = Processes Status

pty = pseudo tty

pushd = PUSH Directory

pwd = Print Working Directory

rc = runcom = run command, rc还是plan9的shell

rev = REVerse

rm = ReMove

rn = Read News

roff = RunOFF

rpm = RPM Package Manager = RedHat Package Manager

rsh, rlogin, rvim中的r = Remote

rxvt = ouR XVT

seamoneky = 我

sed = Stream EDitor

seq = SEQuence

shar = SHell ARchive

slrn = S-Lang rn

ssh = Secure SHell

ssl = Secure Sockets Layer

stty = Set TTY

su = Substitute User

svn = SubVersioN

tar = Tape ARchive

tcsh = TENEX C shell

tee = T (T形水管接口)

telnet = TEminaL over Network

termcap = terminal capability

terminfo = terminal information

tex = τέχνη的缩写,希腊文art

tr = traslate

troff = Typesetter new ROFF

tsort = Topological SORT

tty = TeleTypewriter

twm = Tom’s Window Manager

tz = TimeZone

udev = Userspace DEV

ulimit = User’s LIMIT

umask = User’s MASK

uniq = UNIQue

vi = VIsual = Very Inconvenient

vim = Vi IMproved

wall = write all

wc = Word Count

wine = WINE Is Not an Emulator

xargs = eXtended ARGuments

xdm = X Display Manager

xlfd = X Logical Font Description

xmms = X Multimedia System

xrdb = X Resources DataBase

xwd = X Window Dump

yacc = yet another compiler compiler

Fish = the Friendly Interactive SHell

su = Switch User

MIME = Multipurpose Internet Mail Extensions

ECMA = European Computer Manufacturers Association

git代码托管服务之码云其实也不错

被我忽视的代码托管gitee码云

其实在2015年码云这个词出来的时候,就大概知道它是干嘛的,但是,也许是高度跟马云爸爸重名的原因吧,很是避讳,而且当时github作为业界的标杆,无论是成熟度还是知名度都不是后来者码云能比的,所以也就没有去使用这个产品。为什么现在开始要使用了呢?原因如下:

  • 网速
  • 网速
  • 网速

总要的事情说三遍。。。其实还有其他原因,是因为码云的功能也对标github了,提供的定制服务也想当健全了,虽然对我来说我还没用上(笑),但是有一个很重要的东西,不能没有。之前一直忽视码云,感觉身边人用的也少,一不小心错过了它发展的新闻,竟然最近才得知,码云其实也支持pages功能,虽然人家在2016年就开始提供这个服务了。(笑哭)

不想放弃github也想托管码云,怎么办

码云是后来者,所以提供了一个可以导入项目的功能,这个可以直接将github上的代码同步到码云上来,很方便。然后就是在本地开发,想要同步两个仓库的问题。以前,我们没有这个问题,我们直接是一个远程origin,这一套玩儿法我们已经很熟悉了,那再来一个仓库,要怎么同时同步呢?答案对于超级熟悉git的人来说应该很容易,但是很多人是只是熟悉普通的git命令, 大家通常是去百度或者google,其实我也是(笑),嘿嘿。百度之后,就知道,一个本地git项目其实是很容易可以添加两个甚至多个远程仓库的,命令为git remote add [name_your_remote_channel] master

说说码云的pages功能

码云的pages功能相比于github的pages功能,对于我们国内来说有,那速度就爽翻了,个人展示类项目和博客,打开速度从此告别2G时代,很爽。

对PWA(Progressive Web Application)的认识

前言

时间大概是在2016年,google推出了PWA技术,旨在提升web app的用户体验, 总体来说,这个技术将会对web应用的普及及市场占有率推向新的高潮,它的意义是非凡的,可以说是下一代的web应用模型。下面简要罗列一下我对web app的劣势和优势的认识,来一窥PWA技术是如何弥补web app的不足的。

web app的优势

  • 轻量,不用下载
  • 开发成本低
  • 跨平台能力强
  • 用户获取成本低
  • 迭代快

web app的劣势

  • 体验较native app弱(离线体验,动效,消息推送等)
  • 无一级入口(native级别的入口)

google的PWA技术

针对web应用比较大的两个劣势,google推出了自己的解决方案——PWA技术。PWA技术主要分两个方面,分别针对以上分析的web app的劣势。

  • 用service-worker技术来弥补离线体验和消息推送方面的劣势
  • 用manifest.json的实现,使得web app可以添加到系统桌面并以native app一样有全局窗口,而不是打开浏览器的体验

最后

这里对于PWA应用的实现,我就不做介绍了,因为官网文档实在是太细致了,跟着官网的教程,你绝对能实现一个PWA应用,并对其有一定的认识,比各种百度google要强很多(亲身体验…)。

google PWA 教程

我翻译的google PWA教程

使用nodeJS来做一个cli工具

前言

nodeJS是javascript的一个运行环境,是基于chrome v8引擎的封装,由于其具备的一些优点,使得它极大延伸了javascript的用武之地,本篇文章就是探索实现一个基于nodeJS环境的cli工具。

准备工作

安装nodeJS(此处省略100字…)

撸代码

代码没啥好说的,你想实现怎样的一个cli工具,你就使用nodeJS相应的api去封装,去实现功能,唯一额外需要注意以下跟代码不太相关的东西:

  • 由于是使用node作为运行环境,因此命令行工具执行文件头部需要指明环境,一般为:#!/usr/bin/env node

  • cli工具需要全局使用或者供他人使用,你需要按照npm包的编写规则来组织代码结构,包的规则最基本的是,你需要有一个package.json的文件,及一个bin目录,package.json对bin目录需要进行描述,其描述的键值对中,键会在发布后作为cli命令的关键字,值即为cli命令指向运行的js脚本。具体示例如下:

...
"bin": {
  "cli-command-name": "bin/index.js"
}
...
  • 编写过程需要注意,如果需要给不同操作系统用,需要注意windows与unix的会有差别。一般来说unix系统上编写的cli命令可在windows上运行,而在windows上编写的cli命令工具,在unix系统上会报错

  • cli命令最好不要与npm包中其他已发布的包重名,可以先去npm官网去搜下

  • 编写命令行cli工具可以借助一个第三方库commander.js

  • 在发布前,可以先使用npm link将包内容发布到本机全局部署,然后就可以在本机上使用该cli命令

  • 发布后给人使用的系统中,请务必保证有nodeJS环境,否则无法生效

发布

首先,你需要一个npm账号;然后就是简单的一些操作命令,如npm login, npm publish。此时发布的代码只是在npm托管的,如果你想把代码开源托管在github上,你需要自己上传到github上,同时你可能注意到,其他很多npm包都有链接跳转到github的开源代码处,如果你熟悉package.json文件的配置和npm官网的显示规则,就会知道,你需要再package.json中加入一段如下代码:

"repository": {
  "type": "git",
  "url": "git+https://github.com/Andrewuetyang/rname-cli.git" // git + 后面是你的npm包在github上的托管位置
},

另外发布过程中,可能会遇到发布不成功报403,这极有可能是因为npm注册是淘宝镜像,需要切换回原地址。

最后

嘿嘿,自己在学习这个后,我的第一个cli工具是写了一个可以批量重命名文件名的工具,由于这种工具已经很多了,所以关键字被占用了,只能取了一个rname-cli这样的命令名字,吨吨吨…自己写的cli符合自己的使用习惯,是的,虽然有很多这种rename工具,但是不喜欢他们的规则,自己写的用的很爽。

webpack2及以上的tree-shaking功能探索

从很容易就会思考的一个问题开始

以下代码是es6语法关于模块导入的,当我们使用webpack打包的时候,很自然会想到这个打包过程是将整个模块打包进来还是我要用的即引入的部分打包进来呢?

import { a } from './module'

a()

在webpack1的时候,这个打包过程是将整个模块打包进来,不管你这个文件使用了模块多少的代码。显然,这是不合理的,理想情况,我们更愿意见到使用的部分打包进来,其余部分最好给我们清理掉,打包一堆没用的东西进来,占用了bundle的体积。据说最开始,rollup.js(前端打包工具,跟webpack是同类型产品),实现了这个功能,并起了一个非常形象的名词,叫tree-shaking。webpack2开始,也加入了这个功能。

那么webpack的tree-shaking要如何开启呢?

其实很简单,需要有几个前提条件:

  • webpack2.0及以上
  • 使用了es6的模块语法导出导入
  • 使用了uglifyJS压等压缩工具压缩代码

发现的问题

以上是网上说的比较多的,但是本人在使用过程中发现,还需要注意一个细节,那就是在配置babelrc(指所有配置babel的配置,其他可配置babel的地方如webpack配置babel-loader的options,还有package.json)时虽然可以归并到第一个前提条件,但是容易被忽略。

这个细节就是,配置presets时,一定要将modules设置为false,这个如果没设置,就没卵用,作者亲身体会。现在看看,这个设置理所当然,因为即使你使用了es6的语法来处理模块,在没设置这个参数时,默认是true,也就是默认将es6等的语法转换成common.js。

下面用实验代码来证实一下吧。(本次使用webpack3)

没有配置modules为false即modules默认值为true

index.js文件代码

import { a } from './module'

a()

module.js文件代码

export function a() {
  console.log('a');
}

export function b() {
  console.log('b');
}

webpack.config.js文件代码

const path = require('path')
const webpack = require('webpack')

module.exports = {
  entry: path.resolve(__dirname, 'index'),
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].bundle.js'
  },
  module: {
    rules: [{
      test: /\.js$/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['env']
        }
      }
    }]
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin()
  ]
}

打包得到的文件index.bundle.js代码,注意,此时打包的文件里面是可以查到有关b函数的定义的,并没有shaking掉。

!function(n){function e(o){if(t[o])return t[o].exports;var r=t[o]={i:o,l:!1,exports:{}};return n[o].call(r.exports,r,r.exports,e),r.l=!0,r.exports}var t={};e.m=n,e.c=t,e.i=function(n){return n},e.d=function(n,t,o){e.o(n,t)||Object.defineProperty(n,t,{configurable:!1,enumerable:!0,get:o})},e.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return e.d(t,"a",t),t},e.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},e.p="",e(e.s=1)}([function(n,e,t){"use strict";function o(){console.log("a")}function r(){console.log("b")}Object.defineProperty(e,"__esModule",{value:!0}),e.a=o,e.b=r},function(n,e,t){"use strict";(0,t(0).a)()}]);

配置modules为false

对webpack.config.js的配置更改部分

options: {
  presets: [
    ['env', {modules: false}]
  ]
}

打包结果—无b函数定义

!function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var n={};t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=1)}([function(e,t,n){"use strict";function r(){console.log("a")}t.a=r},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(0);n.i(r.a)()}]);

完!

当前阶段对函数式编程的认识感受

废话不多说,直接进入今天的话题,函数式编程。这个名字很高大上,最近几年在编程届也是炙手可热,大家都很推崇。那么问题来了,函数式编程是什么,究竟要解决什么问题,它又有着什么样的思想,是否有缺点呢。

什么是函数式编程?

网上一搜,有很多解释:

函数式编程是种编程方式,它将电脑运算视为函数的计算。函数编程语言最重要的基础是λ演算(lambda calculus),而且λ演算的函数可以接受函数当作输入(参数)和输出(返回值)。和指令式编程相比,函数式编程强调函数的计算比指令的执行重要。和过程化编程相比,函数式编程里函数的计算可随时调用。

与面向对象编程(Object-oriented programming)和过程式编程(Procedural programming)并列的编程范式。最主要的特征是,函数是第一等公民。最主要的特征是,函数是第一等公民。

还有非常通俗的认识:

函数式编程与命令式编程最大的不同其实在于:函数式编程关心数据的映射,命令式编程关心解决问题的步骤,这里的映射就是数学上「函数」的概念——一种东西和另一种东西之间的对应关系。这也是为什么「函数式编程」叫做「函数」式编程。

嗯,很好,我若有所思的样子。。。额。。。

函数式编程的特征

综合所看的一些资料,主要说到关于运算的合成和柯里化。合成即是说一个值需要经过多个函数演变成另一个值,就可以把这些中间步骤的函数合并成一个函数。函数柯里化,形式上来说就是把一个多个参数的函数,转变成一些了单参数的函数。

函数式编程想要解决的问题

综合之前看过的一些资料和自己的一些理解,这个范式其实是想更语义化的用函数而不是指令将计算过程表达出来,这样表现出来的就是一种数据的映射,让人理解起来非常一目了然。这样,计算过程不再杂乱,而是由具体的函数单元,执行一个个具体的计算过程,而不是将一堆计算过程放在一起,代码的阅读和维护性方面会更好。这样演变,如果可能的话(作为一个菜鸡,不确定这个结论,吨吨吨),也许写业务代码就可以利用这些函数库还有更高级的函数库,像人类语言那样的描述,让代码工作起来,岂不快哉。当然,现阶段很难达到。而且个人认为可能永远行不通。因为我算了一笔账(可能不正确,但是whatever),计算过程被函数封装,以最基本的单元,那光是语义化的计算单元封装出来的,应该是一个很大的数字,然后基于这些函数单元合成出来的函数,我了个去,不可想象。

虽然如此,但我也是矛盾的,诚惶诚恐的。毕竟语言就是这么发展的,从机器二进制码,到晦涩难懂的汇编,再到c这种中级语言,最后到现在大多数程序员在使用的高级语言,让编程变得更加容易。这些都是逐渐变得语义化,借助编译器将计算过程breakdown到底层。还是很期待那一天,使用人类自然语言,控制各种计算过程,人类的能力将无可限量。

Vue SSR学习小结

前言

ssr即服务器端渲染,是一个有利于SEO,及首屏加载等优势的一种view层的处理。ssr简单来说就是在保持前后端分离的开发模式下,在前后端中间加一个node中间层,在node中间层对页面数据进行组装,即node层去请求后端数据,然后在html模板进行填充,完了之后就返回给客户端。缺点也有,可以参考官方文档。选取时,最好综合考虑。

为什么会出现这种技术?

当前SPA应用是彻底的将内容变成服务器端的一种服务,后端对于前端来说,就是提供动态数据的服务人员。SPA技术将内容和模板的结合放在浏览器端,内容是通过ajax异步获取的。这样的话,根据搜索引擎原理,必然导致SEO很烂。同时,如果客户端网络环境差,也会延长内容到达时间。SSR就是来解决这个问题的。这项技术已经经过充分实践了,最典型的例子就是手机淘宝app,据淘宝内部团队人员透露,目前手机淘宝app里绝大部分的页面都是SSR技术,即他们口中所说的,在服务器端和客户端之间加一个node中间层来渲染页面,手机淘宝的体验,相信绝大多数中国人都是有体验的,非常完美。

核心思想

在node层进行内容数据预取,然后在html模板中进行填充,返回客户端进行展示。

vue SPA应用的SSR构建

将spa应用处理为ssr的模式,还是有很大的复杂性的。当然,社区繁荣一片的现在,你可以使用开源的NUXT.js,来做ssr处理。要想自己有更多的项目结构控制权的话,就需要知道这些东西是怎么根据构建工具串起来的了。在我经过了几天学习官方文档之后,我试着总结一下这个串接过程。在讲述串接过程前,先需要知道vue作者的ssr构建的设计。

首先顶层上,有1个工具叫vue-server-renderer。这个模块负责支持整个构建过程必要环节的处理。这个工具下,提供了一些模块和api。在一个基本的构建过程中需要用到的有:

api: createBundleRenderer // 创建renderer,renderer的作用是将vue实例渲染成html

模块:client-plugin和server-plugin // webpack插件,分别处理客户端打包和服务器端打包

为了将相同的应用程序提供给客户端,我们使用webpack来打包构建。ssr同样也需要打包构建。因此作者的基本思路就是,对服务器端渲染打包成一个bundle,对客户端程序打包成一个bundle。在客户端发起请求的时候,返回服务器对应的渲染页面和客户端bundle,由于服务器端渲染页面已经留下了静态标记,客户端bundle会识别这个标记,并以混合模式挂载(具体怎么实现的需要去阅读源码)。

最后输出应用程序

有了构建工具构建出来的工件,可以进一步输出程序。基本思路是借助createBundleRenderer根据打包好的bundle创建一个renderer,然后在node服务器的帮助下,根据请求路径来确定一个context上下文对象,renderer再依据这个context,返回必要的静态资源给客户端用于展示。

webpack学习再回顾

在我的心中,webpack是一个变革者,他提供了前端一个全新的开发模式,并将这一职业推向一个新的高点。

追溯webpack的起源

这些年互联网发展迅速,越来越多的网站以及web应用的需求不断增加,一个井喷的web程序井喷的时代,为数不多的程序猿们,如何应对呢?自然,得提高效率嘛,于是大家就想办法提高效率,怎么提高呢?啦啦啦,此处省略一千字,答案是web设计师行业开始变更为前端工程师,前后端概念出现,简单的说,前端负责人机交互、内容的良好呈现、把需要的信息提交给后端,而后端即服务器端,负责处理服务器问题、与前端交互、以及数据的处理并与数据库交互。这样初步解决了团队效率问题。日复一日,程序越来越复杂,前端的代码量开始增多,代码维护性出现了性功能问题,哈哈。于是渐渐的,为了解决前端开发工程化复杂的问题,使其代码更加结构化、维护性更好,出现了grunt、gulp、webpack等工具。

webpack概念

webpack 是一个现代 JavaScript 应用程序的模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成少量的 bundle – 通常只有一个,由浏览器加载。

它是高度可配置的,但是,在开始前你需要先理解四个核心概念:入口(entry)、输出(output)、loader、插件(plugins)。不详细解释,如有需要,见其官网。

webpack能力大致描述

我们都知道,前端从大致的方向上看,主要关注点在四个方面,一个是html模板,一个是css样式,一个是javaScript负责的行为逻辑,最后是其他资源,如图片。

  • js需要模块打包,好的,简单的说,webpack内部使用了browserify来处理commonJS和es6的模块的依赖关系来完成打包。你写的jsx语法、es6语法等,浏览器不支持不兼容怎么办?没关系,提前准备了babel的编译器,实现优雅编译。js想要丑化压缩下,没问题,咱有插件系统。

  • 对于css文件,由于webpack本身只理解javaScript,css文件如何打包呢?简单的说,借助loader来实现,css-loader和style-loader就是很好的任务完成者。css-loader出色的完成了css模块化的问题,style-loader出色的完成了在html中对模块化的css插入问题。你写了less,好的,聪明的开发者搞了个less-loader,负责less的编译问题。

  • 图片想要处理下,base64能做得到吗?没问题,咱有url-loader。资源想要集中化一下,没事咱有file-loader。

感受webpack的架构

nodeJS诞生后,各种前端自动化工具成为了可能。webpack出色的架构,很好的解决了自动化过程中需要处理的问题。在我看来,webpack将资源处理或者说应用程序源代码处理,看做一个文件流,甚至可以形象的比喻为一根有很多处理工厂的管道,从这头到那头的过程,自动识别要处理的资源,进行预先设定的加工处理,然后输出。加工厂可以自定义无限扩展,主要分成两类,一类是loader,一类是plugins。loader主要是做文件转换工作的。而plugins是用来做loader不能做的事儿的,因为loader局限在了文件转换,而在打包的生命周期需要执行的任务,它无法完成,插件就是来做这个工作的,比如打包完成需要对js进行执行uglify,这个时候就需要插件来完成这个任务。

废话说完了,嘻嘻。

纯前端canvas俄罗斯方块小游戏实现

小时候打的第一款游戏,说起来大概就是俄罗斯方块了,这种游戏老少咸宜,设计的非常巧妙,不高冷,不装逼,之前查询过这个游戏的过往,发现那些年火爆经典的游戏中,俄罗斯方块的火爆经典程度简直超乎我的想象。其实仔细想下,其实我们的确可以自己来实现一个类似的游戏。于是乎,经过多天的构思和参考别人写过的demo,我也自己实现了一遍,下面我就来谈谈自己的俄罗斯方块。

我的俄罗斯方块

功能点罗列

  • 地图数据结构
  • 方块数据结构
  • 地图生成
  • 地图绘制
  • 地图更新
  • 方块创建
  • 方块擦除
  • 方块下落
  • 方块的方向键操作
  • 方块变形
  • 方块满行消除
  • 方块触底检测
  • 方块左右碰撞检测

当然还有canvas元素的处理,这里就不说了。

地图数据结构

使用0, 1这样的数字来代表有无方块,地图上无方块时,就都是0. 示例如下:

[
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
]

方块数据结构

跟地图类似,使用0,1来代表形状,总结归纳出方块的几种情况:

[
    [1, 1, 1, 1]], // 一字形
    [[1, 1], [1, 1]], // 田字形
    [[1, 1, 0], [0, 1, 1]], // z字形
    [[0, 1, 1], [1, 1, 0]], // 反z字形
    [[1, 0, 0], [1, 1, 1]], // L字形
    [[0, 0, 1], [1, 1, 1]], // 反L字形
    [[0, 1, 0], [1, 1, 1]] // T字形
]

地图生成

我们将地图控制的变量明确出来,这样就可通过设置控制地图的生成。 这些变量是,多少行,多少列,一个格子多大,格子间距多大,方块生成初始化时离x轴起点的位置,方块下落速度, 加速下落速度等。

var tetrisGame = new Tetris({
    row: 12,
    col: 12,
    grid: 30,
    margin: 10,
    offsetX: 4,
    interval: 400,
    fasterInterval: 100
})
tetrisGame.start()

地图绘制

根据地图的数据,借助canvas提供的api(就两个api就可以搞定,分别是fillStyle和fillRect),给不同的数据点绘制不同的颜色。

// 地图绘制
render: function () {
    var map = this.map
    var mRowLen = map.length
    var mColLen = map[0].length
    var margin
    var grid = this.etting.grid
    margin = this.setting.margin
    for (var i = 0; i < mRowLen; i++) {
        for (var j = 0; j < mColLen; j++) {
            if (!map[i][j]) {
                this.ctx.fillStyle = 'grey'
            } else if (map[i][j] === 1) {
                this.ctx.fillStyle = 'orange'
            }
            this.ctx.fillRect(j * (grid + margin), i * (grid + margin), grid, grid)
        }
    }
}

地图更新

方块的移动需要地图做更新操作,方块就是地图中的一部分,它的移动其实就是每个格子状态根据一定的算法来改变,达到动画的效果的。因此地图或者说游戏的更新,就是根据方块当前的位置和方块本身的数据结构来更新的。

方块创建

方块的生成是随机的,利用js的随机数以及预定义好的方块数据结构,很容易做到。然后根据我们预设的方块的初始化的位置,就可以在地图中生成。

方块擦除

方块是随着时间运动的,直到触底。因此在运动的时候,我们根据时间的特性,下一个状态的方块来临之前,我们将上一个状态的方块清掉,这里注意的是,只清除那些格子有形的部分,否则会出现当与其他已定方块耦合时,将已定方块的某些部分也清除了。

方块下落

方块下落使用定时器来处理,每一个时间点,做一次清除然后增加方块y轴的值,然后再更新地图。同时在下落的时候,需要判断是否落地。

方块的方向键操作

根据keydown事件和keyCode的值,我们给不同的方向键提供不同的处理方法。向上时,我们做方块变形,向下时,我们加速下落,左右键做左右移动操作。

// 方块移动及变形操作
enableKeyControl: function () {
    var _this = this
    document.onkeydown = function (e) {
        switch (e.keyCode) {
            case 37: // 向左
                if (!_this.borderTest(_this.curBlock, -1)) {
                    _this.clearBlock()
                    _this.x--
                    _this.updateMap()
                }
                break
            case 39: // 向右
                if (!_this.borderTest(_this.curBlock, 1)) {
                    _this.clearBlock()
                    _this.x++
                    _this.updateMap()
                }
                break
            case 38: // 向上即变形
                _this.clearBlock()
                _this.transform()
                _this.updateMap()
                break
            case 40: // 向下即加速
                if (!_this.onkeydownFlag) {
                    _this.onkeydownFlag = true
                    clearInterval(_this.timer)
                    _this.fall(_this.setting.fasterInterval)
                }
                break
        }
    }
    document.onkeyup = function (e) {
        if (e.keyCode === 40) {
            _this.onkeydownFlag = false
            clearInterval(_this.timer)
            _this.fall(_this.setting.interval)
        }
    }
}

方块变形

方块变形就是方块的旋转,我们通常喜欢顺时针来旋转,比较舒服,当然你喜欢逆时针,也可以做的。我是用的顺时针。所以根据旋转的规律,就可以根据旋转前方块的数据结构得出旋转后的数据结构。这里也需要注意一点,是否可以旋转,需要判断,因为有时候一旋转出了边界,一旋转和底部实体融合了,等等。判断的方法是,方块的数据暂时不变更,我们将旋转后的数据,去做测试,判断是否触底或超出边界,即去做方块触底检测和左右方向碰撞检测,如果没有碰撞,就更新方块的数据,如果有,就不允许更新方块数据。

// 方块变形
transform: function () {
    var result = []
    var curBlock = this.curBlock
    var blockRowLen = curBlock.length
    var blockColLen = curBlock[0].length
    for (var i = 0; i < blockColLen; i++) {
        result.push([])
        for (var j = 0; j < blockRowLen; j++) {
            result[i][blockRowLen - j - 1] = curBlock[j][i]
        }
    }
    if (
        !this.groundTest(result) &&
        !this.borderTest(result, -1, true) &&
        !this.borderTest(result, 1, true)
    ) this.curBlock = result
}

方块满行消除

满行的条件触发是以方块落地开始的,所以落地判断成功,就应该需要去判断是否满行,然后做相应的处理。满行的判断,是通过遍历整个地图,看是否有那么些行的格子里都填满了,如果是就需要消除,消除就是在地图的数据结构中,干掉这一样,当然,这个时候的同时,我们可以在地图的最前面行unshift一个充满空格子的空行。

方块触底检测

触底分为两种情况,第一种,是最底部,这个很好判断。第二种,是与其他已经落下的方块之间的判断,看是否还需要往下走。第二种判断方法是,先判断方块的最底部那一行,如果有实体的地方对应的正下方的地图的格子也是实体,那么就不应该再下落,也就是说触底了,如果没有,就去对底部没有实体的那些列去做while循环,向上找到方块的实体格子,这个是总能找到的,因为方块的设计缘故,找到后,就也做类似的判断,看这个方块处的格子对应的正下方地图的格子是否是实体,进而判断是否触底。

方块左右碰撞检测

左右碰撞也分为两种,一种是边界,一种是与其他方块。这里碰撞后,下落还是继续的,不是停止。这个地方的判断,归根结底,其实和下落时与其他方块的判断很类似,只是判断的时候换了一个方向而已。

啦啦啦,终于写完啦。这个简易的俄罗斯方块的代码我上传到了github,看源码请参考https://github.com/Andrewuetyang/tetris

websocket通信的实现

什么是websocket?用处是什么?

WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。通俗的说,就是基于TCP的HTTP协议只能客户端发起请求,服务器来应答,是单向的,而现在这个协议,使得服务器变得更加灵活更加聪明不那么高冷了而也有主动的一面了,同时减少了很多客户端资源的浪费。

搬个场景来说明它的好处(http协议下的ajax轮询场景):

客户端:啦啦啦,有没有新信息(Request)

服务端:没有(Response)

客户端:啦啦啦,有没有新信息(Request)

服务端:没有。。(Response)

客户端:啦啦啦,有没有新信息(Request)

服务端:你好烦啊,没有啊。。(Response)

客户端:啦啦啦,有没有新消息(Request)

服务端:好啦好啦,有啦给你。(Response)

客户端:啦啦啦,有没有新消息(Request)

服务端:。。。。。没。。。。没。。。没有(Response) —- loop

为了解决这种问题,于是出现了websocket技术。就说这么多,如果想了解更多可以去查找更多的资料,接下来我们就来实现一个这样的通信。

基于node的websocket通信的实现

nodeJS的socket.io模块可以很简单的让你将websocket通信玩起来。还是直接上代码吧,以下是一个非常简单的聊天室用户登录栗子,大家可以实时看到哪些人上机了。

下面是服务器端代码:

// 引入必要的模块
var http = require('http')
var express = require('express')
var sio = require('socket.io')
var fs = require('fs')

var app = express()
var server = http.createServer(app)

app.get('/', function (req, res) {
    res.sendFile(__dirname + '/index.html')
})

server.listen(3000)

// socket.io监听服务器得到一个io对象,可对websocket做处理
var io = sio.listen(server)

var names = []

// 监听连接事件,连接成功可获得一个socket对象,可对websocket通信进行处理
io.on('connection', function (socket) {
    socket.emit('login', names)
    socket.on('login', function (data) {
        names.push(data)
        io.sockets.emit('login', names)
    })
})