资讯专栏INFORMATION COLUMN

前端架构(git、模块化)

alanoddsoff / 2677人阅读

摘要:仅作用于未跟踪的文件。作用是保存目前的工作目录和暂存区状态,返回一个干净的工作空间。用于标记某次发布。模块仍然污染了全局变量。实际返回的是这个函数,参数包括模块名,依赖的模块,当前模块的实现。

协作流程 1.职责 页面工程师

前端工程师

接口设计

1.页面入口规范

基本信息

输入参数

模板列表
接口列表

2.同步数据规范

基本信息

预填数据

注入接口

3.异步接口规范

基本信息

输入数据

输出结果

同步请求,异步请求? 版本管理

版本控制系统VCS (Version control system)

1.分支模型

产品级的分支模型:

2.git

git是一个基于内容寻址的存储系统。基于文件内容,而不是基于文件。

安装

Windows: msysgit http://msysgit.github.io

Mac: brew install git

Ubuntu: apt-get install git

git基础操作 1.git config

用户配置:

git config --global user.name "Darcy"
git config --global user.name text.example.com

配置级别:

2.git init

初始化之后会出现一个.git/目录,下面存储着包括config文件在内的几乎所有git相关文件。

3.git status

跟踪:track

4.git add

添加文件内容到暂存区,同时文件被跟踪

批量添加: git add . 添加当前目录所有文件

5..gitignore

如果有不希望跟踪的文件,那么需要配置忽略文件。

仅作用于未跟踪的文件。

gitignore常见配置:github中的示例

6.git rm

暂存区删除文件。

git rm --cached 仅仅从暂存区删除

git rm 同时从暂存区和工作目录删除

git rm $(git ls-files --deleted) 删除所有被跟踪,但是在工作目录被删除的文件

7.git commit

提交。

git commit -m "initial commit"

git commit -a -m "initial commit" 直接提交

8.git log

提交历史记录。

git log

git log --oneline 只有7位hash和提交时输入的commit message

git log --color --graph --pretty=format:(此处省略2行) 更美观,且有分支链

上面的命令太长了,不可能每次都这样输入,因此需要配置别名alias

语法:git config --global alias.shortname

例子:git config --global alias.lg "log --color --graph --pretty=format:(此处省略2行)"
这样就可以用 git lg 来表示上面那行命令了。

别名其实也存储在gitcofig文件中

9.git diff

显示版本差异。

git diff 工作目录与暂存区的差异

git diff -cached[] 暂存区与某次提交的差异,默认是,指向当前的提交

git diff [] 工作目录与某次提交的差异

10.git checkout --

撤销本地修改。

即:将工作内容从暂存区复制到工作目录。

11.git reset HEAD

取消暂存。

即:将文件内容从上次提交复制到暂存区。

12.git checkout HEAD --

撤销全部改动:取消暂存 + 撤销本地修改。

git分支操作 13.git branch

git branch 新建分支

git branch -d 删除指定分支

git branch -v 显示所有分支信息

14.git checkout

通过移动HEAD检出版本,可用于分支切换。

git checkout 切换分支

git checkout -b 新建一个分支并切换到新分支

git checkout -b 切换到其他引用对象,比如 commit id 或 标签

git checkout - 回到上一个分支(把HEAD移动到上一个分支)

15.git reset

将当前分支恢复到某个历史版本。以下三种模式的主要区别是内容是否会恢复到工作目录和暂存区。

git reset --mixed e33e42 --mixed是默认参数,不写也行,当前内容(即原来的提交)会被复制到暂存区

git reset --hard e33e42 --hard 时,当前内容(即原来的提交)会被复制到暂存区和工作目录

git reset --soft e33e42 --soft时,暂存区和工作目录都不会有任何改变,原来的提交变成了一个无索引的提交,有可能会被回收,可以用 git reflog 找回来

捷径:git reset HEAD^/HEAD~1/HEAD~n HEAD的上一次提交,前第n次提交

区分resetcheckout 在操作分支与操作文件时的不同

16.git stash

我们在git checkout切换分支的时候,经常会被提示“当前有未提交的内容,请commitstash”,而我们通常是写到一半不希望commit的,所以这时就需要git stash

作用是:保存目前的工作目录和暂存区状态,返回一个干净的工作空间。

git stash save "push to stash area" 第一步:保存

git stash list 第二步:查看已有列表 会显示:stash@{0}: On master: push to stash area

git stash apply stash@{0} 第三步:把保存的内容恢复到工作目录

git stash drop stash@{0} 第四步:把对应的stash命令删除掉

git stash pop stash@{0} 捷径:第三步+第四步

17.git merge

假定当前在master分支。

git merge next 合并 next 分支的内容到master分支

如有冲突,会是下面这样:

<<<<<<< HEAD

next 

=======

origin/master

>>>>>>> origin/master

====上面指当前分支的提交,下面是要merge过来的分支的提交内容。

18.git rebase

修剪提交历史的基线,俗称“变基”。

git rebase master

不要在共有分支使用rebase。

19.git tag

标签,一个不变的别名。用于标记某次发布。指向一个commit对象。

git tag v0.1 e39d0b2

打完标签之后,可以直接使用标签名切换分支: git checkout v0.1

git远程操作 20.git push

提交本地历史到远程。

21.git remote

git remote add origin ~/git-server 添加一个远程仓库别名origin

git remote -v 查看远程仓库信息

22.git fetch

获取远程仓库的提交历史。

git fetch origin/master

git merge origin/master

23.git pull

git pull

=git fetch + git merge

23.git clone

获取一个远程仓库作为本地仓库。

git clone ~/git-server test2 会克隆远程仓库到 test2目录下

技术选型 模块化(JS) 一、模块 1.模块的职责:

封装实现

暴露接口

声明依赖

2.第一步:没有应用任何模块系统(反模式 Anti-Pattern)

math模块:

//math.js
function add(a, b) {
  return a + b;
}
function sub(a, b) {
  return a - b;
}

caculator模块:

//caculator.js
var action = "add";

function compute(a, b){
  switch(action){
    case "add": return add(a, b);
    case "sub": return sub(a, b);
  }
}

可以看出 caculator模块是依赖math模块的。

math模块特点:

无封装性:变量全部散落在全局里。

接口结构不明显:如果我们没有简化代码,那么并不能清楚的知道math到底输出了哪些接口

caculator模块特点:

没有依赖声明:依赖了math模块但是却没有声明。

使用全局状态:使用了action这个全局状态,应该尽量避免。

3.第二步:使用字面量(Object Literal)优化

math模块:

//math.js
var math = {
  add: function add(a, b) {
    return a + b;
  }
  sub: function sub(a, b) {
    return a - b;
  }
}

caculator模块:

//caculator.js
var caculator = {
  action: "add",
  compute: function compute(a, b){
    switch(action){
      case "add": return add(a, b);
      case "sub": return sub(a, b);
    }
  }
}
math模块特点:

结构性好:用字面量把接口进行了结构化。

访问控制差:依然没有进行控制。

caculator模块特点:

依然没有依赖声明:依赖了math模块但是却没有声明。

无法设置私有属性action虽然是成员属性,但在外部依然可以访问到。

4.第三步:使用立即执行的函数表达式IIFE(Immediately-invoked Function Expression)解决无法设置私有属性的问题。

caculator模块:

//caculator.js
var caculator = (function(){
  var action = "add";
  return {
    compute: function compute(a, b){
      switch(action){
        case "add": 
          return math.add(a, b);
        case "sub": 
          return math.sub(a, b);
      }
    }
  }
})();
caculator模块特点:

依然依然没有依赖声明:依赖了math模块但是却没有声明。

有了私有属性action是我们要的私有属性,compute函数可以访问到,而且在caculator外面无法访问到。

5.第四步:增加依赖声明

caculator模块:

//caculator.js
var caculator = (function(m){
  var action = "add";
  function compute(a, b){
    switch(action){
      case "add": 
        return m.add(a, b);
      case "sub": 
        return m.sub(a, b);
    }
  }
  return {
    compute: conpute
  }
})(math);
caculator模块特点:

显示了依赖声明:把math模块作为参数传了进去,并且可以对形参进行命名,这里命名为m

math模块仍然污染了全局变量

必须手动进行依赖管理:math模块是手动传进去的,必须手动保证math是在这之前就被加载了。

注意return的部分与原来不一样了:学名叫 揭露模块模式review module pattern,优点是在暴露的模块进行增删查改的时候会非常方便

6.第五步:使用命名空间(name space)解决污染全局空间的问题

帮助我们只暴露一个类似于namespace的全局变量。而不是将math这样的模块都注册在全局作用域中。

math模块:

//math.js
namespace("math", [], function(){
  function add(a, b) {
    return a + b;
  }
  function sub(a, b) {
    return a - b;
  }
  return {
    add: add,
    sub: sub
  }
})
//第一个参数为模块声明,第二个参数为依赖的模块,第三个参数为模块的构成

caculator模块:

//caculator.js
namespace("caculator", ["math"], function(m){
  var action = "add";
  function compute(a, b){
    return m[action](a, b);
  }
  return {
    compute: compute
  }
}

依赖是统一注册在某个地方,而不是全局中的一个变量。

namespace的实现:

cache中缓存了所有的模块。
实际返回的是createModule这个函数,参数包括:模块名,依赖的模块,当前模块的实现。
如果只传入了一个参数,就返回这个模块cache[name]
取得所有依赖的模块deps,即保证前面的模块都已经被定义好了,这样当前模块(这里为caculator模块)才能运行。
最后初始化模并返回定义的模块cache[name]

该方法特点:

不再污染全局环境:把模块都定义在一个namespace变量中。

没有依赖管理:依然是我们手动进行依赖管理。

依赖管理(dependency manage)

如果这些模块分散在不同的文件中,我们在用的时候就要对引入的脚本顺序进行手动排序。
比如 module2.js中依赖了module1.js,那么写的时候就要先写module.js,像这样:


  
  

但是我们在实际开发过程中的依赖总是很复杂。那是一条又长又复杂的依赖链。非要人肉分析是会抓狂的。而这其实是模块系统的工作。

二、模块系统 1.模块系统的职责

依赖管理(加载 / 注入 / 分析 / 初始化)

决定模块写法

2.CommonJS
//main.js
function add(a, b){
  return a + b;
}
function sub(a, b){
  return a - b;
}
exports.add = add
exports.sub = sub

比原来的写法多了接口暴露:exports.add = add exports.sub = sub

//caculator.js
var math = require("./math");

function Caculator(container){
  //...
}

exports.Caculator = Caculator

比原来的写法多了依赖声明: var math = require("./math"); 和 接口暴露:exports.Caculator = Caculator

优点:

运行时支持,模块定义非常简单:只是利用了几个全局变量exports, module, require

文件级别的模块作用域隔离:这几个全局变量的作用域都是文件级别的,虽然JS没有文件级别的作用域,但我们对它进行了封装,使得使用时一个文件有一个作用域,它们使用起来非常安全。

可以处理循环依赖。

缺点:

不是标准组织的规范。

同步的require,没有考虑浏览器环境。而我们的浏览器文件加载是一个异步的过程,这是最大的问题,这是否就意味着我们的浏览器没办法使用了呢?当然不是。现在有很多工具比如browserify,比如webpack,可以帮助我们把多个文件级别的模块打包成一个文件,这样我们引入单个文件就可以在浏览器里使用了。

因为CommonJS天然的不适合异步环境,所以出现了天然异步的AMD(Asynchronous Module Definition)

3.AMD

与我们前面的namespace非常像。

//main.js
define([], function(){
  function add(a, b){
    return a + b;
  }
  function sub(a, b){
    return a - b;
  }
  return {
    add: add,
    sub: sub
  }
})

比原来的写法多了包裹函数:define,第一个参数为依赖的模块列表,第二个参数为当前模块的实现。

//caculator.js
define(["./math"], function(math){
  function Caculator(container){
    //...
  }
  return {
    Caculator: Caculator
  }
}

同时AMD还支持一个简单的CommonJS写法,只不过要用一层函数包裹起来define(function(require, exports){ ... })

优点:

专为异步I/O环境打造,适合浏览器环境。

支持类似CommonJS的书写方式。

通过插件支持可以加载非JS资源。

成熟的打包构建工具,并可结合插件实现一些预处理的工作。

缺点:

模块定义繁琐,需要额外的函数嵌套。

只是库级别的支持,需要引入额外的库,比如requireJS。

无法处理循环依赖。

无法实现条件加载,因为只是库级别的。

4.原生JS语言级别支持的模块化标准ES6 Module(Javascript module definition for future)
//main.js
function add(a, b){
  return a + b;
}
function sub(a, b){
  return a - b;
}
export { add, sub }

比原来的写法多了接口暴露:export {add, sub}

//caculator.js
import { math } from "./math";

function Caculator(container){
  //...
}

export { Caculator }

比原来的写法多了依赖声明: import { math } from "./math"; 和 接口暴露:export { Caculator }

优点:

真正官方的规范,未来的趋势。

语言级别的支持。

适应所有的JavaScript运行时环境,包括浏览器。

可以处理循环依赖。

框架(JS框架) 什么是库和框架

针对特定问题的解答,就有专业性

不控制应用程序的流程

被动的被调用

比如,一个DatePicker时间选择器是一个库,一个Backbone.view是一个框架。

框架

控制反转 Inverse of control <···主要区别

决定应用程序生命周期

一般会集成大量的库

下面这个图很好的解释了控制反转


框架决定了什么时候调用库,什么时候要求你的代码去实现某些功能。

框架和库,他们都是解决方案。关于解决方案,分为7各方面:

DOM

communication 通信

Utility 工具库

Template 模板技术

Component 组件

Route 路由

Architecture MV*架构

1.DOM解决方案 重点:Selector / Manipulation(操作) / Event(dom) / Animation

jQuery

zepto.JS

Mootools

手势支持:Hammer.js

局部滚动:iScroll.js

高级动画:Velocity.js

视频播放:video.js

2.Communication(通信)解决方案 重点:XMLHttpRequest / Form / JSONP / Socket 作用:

处理与服务器的请求与响应

预处理请求数据/响应数据 & Error/Success的判断封装

多种类型请求,统一接口

处理浏览器兼容性

jQuery

zepto.JS

Reqwest

qwest

以上都是异步的请求,但对于实时性要求非常高的产品比如im聊天工具,就需要立即响应。这时需要用websocket。推荐下面的库:

socket.io

3.Utility(工具包)解决方案 重点:函数增强 & shim / Flow Control 职责:

提供JS原生不提供的功能

方法门面包装,使其易于使用。即shim(语言垫片),保证实现与规范一致。

异步队列 / 流程控制 比如promise

3.Template 三种类型:String-based / Dom-based / Living Template

4.Component组件 常用组件: Modal / Slider / DatePicker / Tabs / Editor

Bootstrap

Foundation

5.Routing路由 分类:Client Side / Server Side 职责:

监听url变化,并通知注册的模块,进行页面切换

通过Javascript进行主动跳转

历史管理

对目标浏览器的兼容性的支持

route库

6.Architecture架构(目的:解耦) 分类:MVC / MVVM / MV* 职责:

提供一种范式帮助(强制)开发者进行模块解耦

试图与模型分离

更容易进行单元测试

更容易实现应用程序的扩展

各种框架比较的参考网站:
http://todomvc.com/
https://www.javascripting.com/
https://www.javascriptoo.com/
http://microjs.com/#

7.Component组件 开发实践 系统设计 1.系统说明 2.系统分解 3.接口设计

数据类型(每个页面的每个模块都要多带带定义包含的数据类型列表)

模板资源

异步接口(请求方式,请求地址,输入参数,输出结果)

页面摘要

4.工程构建

项目结构

初始代码

模拟数据

系统实现 1.组件封装

通用原件(logo,输入框,图标,按钮,翻页,复选框列表,loading)

通用列表(歌单。歌手,收藏的节目)

复合组件(比如评论)

浮层弹窗

一个组件(BannerSlifer)的栗子:

2.逻辑实现 测试发布 1.测试联调

本地测试

异步测试

对接联调

2.发布上线

打包发布

优化配置

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/91709.html

相关文章

  • 从零开始做Vue前端架构(9)

    摘要:那该怎么管理这两个不同的项目呢解决子模块用的的同学肯定一下子就想到子模块的知识了。最后,也希望有想法的同学还有大佬多多留言,给点建议原文地址从零开始做前端架构脚手架参考资料官方文档使用定制前端脚手架别人写的脚手架文件操作相关文档子模块 前言 相信很多人都用过vue-cli或create-react-app或者类似的脚手架。脚手架方便我们复制,粘贴,或者clone代码库,而且还可以更具用...

    Vicky 评论0 收藏0
  • 从0开始构建一个属于你自己的PHP框架

    摘要:如何构建一个自己的框架为什么我们要去构建一个自己的框架可能绝大多数的人都会说市面上已经那么多的框架了,还造什么轮子。 showImg(https://segmentfault.com/img/bVNg9F?w=500&h=500); 如何构建一个自己的PHP框架 为什么我们要去构建一个自己的PHP框架?可能绝大多数的人都会说市面上已经那么多的框架了,还造什么轮子?。我的观点造轮子不是目...

    vpants 评论0 收藏0
  • 前端相关汇总

    摘要:简介前端发展迅速,开发者富有的创造力不断的给前端生态注入新生命,各种库框架工程化构建工具层出不穷,眼花缭乱,不盲目追求前沿技术,学习框架和库在满足自己开发需求的基础上,然后最好可以对源码进行调研,了解和深入实现原理,从中可以获得更多的收获随 showImg(https://segmentfault.com/img/remote/1460000016784101?w=936&h=397)...

    BenCHou 评论0 收藏0
  • 某熊的技术之路指北 ☯

    某熊的技术之路指北 ☯ 当我们站在技术之路的原点,未来可能充满了迷茫,也存在着很多不同的可能;我们可能成为 Web/(大)前端/终端工程师、服务端架构工程师、测试/运维/安全工程师等质量保障、可用性保障相关的工程师、大数据/云计算/虚拟化工程师、算法工程师、产品经理等等某个或者某几个角色。某熊的技术之路系列文章/书籍/视频/代码即是笔者蹒跚行进于这条路上的点滴印记,包含了笔者作为程序员的技术视野、...

    shadowbook 评论0 收藏0

发表评论

0条评论

alanoddsoff

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<