Abruzzi

Abruzzi 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑

Front-end Developer,Rocker.
Github: https://github.com/abruzzihraig

个人动态

Abruzzi 赞了文章 · 2015-07-27

ReactEurope Conf 参会感想

React 带来的革命性创新是前端世界过去几年最激动人心的变化。自从接触 React 以来,我深信 React 会改变客户端开发者(包括前端、iOS 和 Android)的开发体验。这次在巴黎举办的 ReactEurope Conf 大会是继第一次在 Facebook 总部举办后最大的 React 活动。超过10位来自React、GraphQL、Relay 团队的核心技术成员也出席大会进行分享。这次代表 Strikingly(似乎也是国内唯一家公司)去参加,想写下一些参会感想。

Keynote 1 讲师是来自 Facebook 的 Christopher Chedeau (vjeux)。他分享了 React 生态系统四大方面 (Data, Targets, Language, Packager)的变化。这次大会所有的内容我觉得也都是这四方面的延伸。我印象最深的是 Data 和 Targets,也是这篇文章主要想分享的内容。

Data

React 定义自己为 MVC 中的 View。这让前端开发者从 V 开始去思考 UI 设计。但现在针对数据操作和获取方式,社区里还没有一种公认的方法。这也是任何写 React 应用时最难处理的地方。

Flux

对于 M 和 V,Facebook 提出了 Flux 的概念。之后,几乎每个月出现一新的 Flux 库,他们都有各自的特色,有的对服务器渲染支持比较好,有的运用了更多函数式编程的概念。很多 Flux 库更像是实验,这有助于 React 生态的生长,但不可否认的是,未来会有大量 Flux 库慢慢死去,而只有少数会存留下来或进行合并。。大会上 React Hot Reload 的作者 Dan Abramov 也介绍了自己新的 Flux 库 - Redux。这也是大会上最受瞩目的演讲之一。Redux 认为 Flux Store 就像函数式编程里的 reducer

f(init_state, action) => state

通过这种方式,我们只要存下所有 action 就可以像时光穿梭一样去到任何时间点上的状态。

Redux 应该是现在最函数式的 Flux 库。私下和 Dan Abramov 的交流中,他告诉我,他正在和其他几位 Flux 库作者接触并有意进行合并,也许 Redux 会是少数存留下的 Flux 库之一。

相关演讲:

1Christopher Chedeau - Keynote

GraphQL / Relay

GraphQL 和 Relay 是我这次参加大会最关心的技术。在构建大型前端应用时,前端和后端工程师通过 API 的方式进行合作。API 也是双方的协议。现在主流的方式是 RESTful API,然而在实践中,我们发现 RESTful 在一些真实生产环境的需求下不是很适用。往往我们需要构建自定义 endpoint,违背了 Restful 的设计理念。GraphQL 是我认为目前最完美的解决方法。这次大会也没有让人失望,推出了 GraphQL 的规范 并 开源了 JavaScript GraphQL 库。

然而要让 GraphQL 成为主流,Facebook 需要打造一个像 React 这样的生态系统。目前只推出了规范 和 GraphQL JavaScript 库(适应于 Node.js 应用)。要想在你自己的应用上用 GraphQL 还必须要有后端语言提供 GraphQL 库的支持。比如 Strikingly 需要 GraphQL Ruby 库。这不仅仅需要前端工程师。我认为这将会比 React 生态系统更难建立。Facebook 需要整个社区的参与才能达到。


(图片来自《Creating a GraphQL Server》[5] 演讲)

Relay

Relay 是 Facebook 提出的在 React 上应用 GraphQL 的方案。React 的基础单位是组件(component),构建大型应用就是组合和嵌套组件。以组件为单位的设计模式是目前社区里最认可的,这也是前端世界的趋势之一。每个组件需要的数据也应该在组件内部定义。Relay 让组件可以自定义其所需要 GraphQL 数据格式,在组件实例化的时候再去 GraphQL 服务器获取数据。Relay 也会自动构建嵌套组件的 GraphQL 查询,这样多个嵌套的组件只需要发一次请求。这次大会也公布了 Relay 将会在8月份开源。

Immutability

React 社区接收了很多函数式编程的想法,其中受 clojure 影响很深。immutable 数据的使用就是来自 clojure 社区。当年 Om,这个用 ClojureScript 写的 React 在速度上居然完虐原生 Javascript 版本的 React。这让整个社区都震惊了。其中一个原因就是 ClojureScript 使用了 immutable 数据。React 社区里也冒出了 immutable.js,这让 javascript 里也能用起 immutable 数据,完美弥补了javascript 做负责数据对象比较的先天性不足。immutable.js 的出现也成为了构建大型 React 应用的必备。本次大会甚至有在讨论是否把 immutable.js 直接纳入 javascript 语言中。我个人认为小型应用不会遇到 virtual DOM 渲染瓶颈,引入 immutable.js 只会让数据操作很累赘。

相关演讲:

2Dan Abramov - Live React: Hot Reloading with Time Travel
3Lee Byron - Exploring GraphQL
4Joseph Savona - Relay: An Application Framework For React
[5] Nick Schrock & Dan Schafer - Creating a GraphQL Server

Targets

对于 Virtual DOM 的讨论,很多人会说速度快过于真正的 DOM。这样的讨论可以让人快速入门理解 React,但是真正写过 React 应用的人会明白速度并不是 Virtual DOM 的精髓。我认为 Virtual DOM 的存在帮助我们做到了两件事。第一是声明式 UI。通过 Virtual DOM,UI 不再是一个不断被更变的 DOM,你只要声明 UI 是怎么生成的,React 会自动帮你把 UI 的改变渲染到真正的 DOM 上。这种新的思维方式让你可以不用手动操作真正的 DOM。第二是多 target。我们一直在讲 web,但 React 让我们做到 web 以外的 target。Virtual DOM 更像是 UI Virual Machine,自动帮你映射到真正的实现上。可以是 浏览器 DOM 、iOS UI、Android UI。在大会上,甚至有人做了 React 映射到 Terminal Text UI [7]。

多 Targets 是这次讨论的主要话题之一。多 targets 的根本是 提高开发者体验。这是本次大会上屡次被提起的概念。我们如何在保持一样的用户体验下,提高开发者体验。

任何一家有多客户端的公司都面临同一个问题:在各种客户端语言里重新造轮子。开发者需要学习新的语言、写和维护类似的功能。提升客户端开发者体验就是减少学习成本和维护成本。这就是 React 提倡的 learn once, write everywhere。

本次大会上也有一些鼓舞人心的消息。Facebook 内部 Ads Manager iOS 版本由 7 位工程师用 React Native 花了 5 个月完成。而 Android 版本,是同一班人,3个月内完成。代码重用率达到了 87%。而且在 React Native 中,大家比较关心的动画效果和速度的问题,也在这次大会上通过 Facebook 工程师 Spencer Ahrens 演讲中的流畅演示得到了令人满意的答案。

多 targets 也可以是在单个平台更深度的结合。这次大会最让我目瞪口呆的是 Sebastian Markbåge 的演讲《DOM as a Second-class Citizen》。演讲中他畅想 React 直接输出到浏览器架构的底层。

图片描述
这是浏览器的渲染架构

图片描述
这是 Sebastian Markbåge 认为 React 可以做的事情。

我当时听完后凌乱了。姑且不谈该不该这么做,我觉得 React 通过 Virtual DOM 能让我们有机会做到就已经让我兴奋不已了。也说明了 Facebook 在设计 React 时已经考虑到超越 DOM。真 TM 的 NB。。。

相关演讲:

[6] Spencer Ahrens - React Native: Building Fluid User Experiences
[7] Mikhail Davydov - Back to Text UI
[8] Sebastian Markbåge - DOM as a Second-class Citizen

其他演讲

篇幅原因,我不详细讨论 Language 和 Packager。但对有几个演讲也留下了深刻印象:

Sebastian McKenzie - Improving Your Workflow With Code Transformation

演讲者是 Babel 的作者 Sebastian McKenzie。Babel 是目前社区里最受欢迎的代码编译工具。Facebook 团队甚至已经决定转用 Babel 而不再维护之前内部使用的 jstranform。

使用 webpack 或 browserify 这类工具编译代码已经渐渐成为前端工程师工作流程的一部分。Sebastian 这次分享了编译代码所带来的好处。他也刚在 Twitter 上宣布加入 Facebook,全心做 Babel。期待未来 Babel 能够带来更多的可能性。

图片描述

Cheng Lou - The State of Animation in React

最早关注 Cheng Lou 是因为他写的 react-tween-state 动画库。一直一来大家都对动画应该在 React 里怎么表达(示)为状态感到困惑。react-tween-state 是我认为最符合 React 思维的做法。把位移存在 state 里,然后通过 javascript 动态渲染新的位置。不过大家对该做法是否能达到满意的速度一直持有保留态度。这次在他的演讲中也展现出了非常出色的效果和速度,非常值得一看。

总结

这次赫门在 JSConf 2015 上提出了前端的摩尔定理:前端每18月会难一倍。虽然他是故意搞笑的,但也确实说明了前端变化的迅速。我觉得前端之所以变化这么快,是因为我们现在面临着前所未有的工程化挑战。今天的前端复杂度跟几年前完全不是一个等级。这也促使着社区要找到在这种复杂度下能保持开发效率和开发体验的工具和设计模式。React 社区从其他领域(游戏渲染、ClojureScript、函数式编程)偷师学艺,结合前端面临的独特问题,提出了一系列解决方案。我觉得 React 社区在各方面都推动着前端社区往前进。这对整个社区都是好事。我也希望前端各个框架,就像 Christopher Chedeau 在 keynote 上说的,停止攻击,互相学习,共同推动整个社区的发展。

It's an exciting time to be a front-end developer.

郭达峰
CTO of Strikingly.com

感谢 题叶、寸志、沈瑜杰、冯哲锐、王徐阳、徐欣 协助修订校对稿件

(这也是 Strikingly 团队做的首次技术分享,之后我们也会继续分享更多的前端技术及相关资讯,请关注我们的专栏)

查看原文

赞 11 收藏 17 评论 0

Abruzzi 赞了回答 · 2015-06-24

解决前端面试题,利用给定接口获得闭包内部对象

基于 @小俞 的方法,我写个可能是更好的选择的吧!

javascriptObject.defineProperty(Object.prototype, 'self', {
    get: function () {return this;},
    set: function (value) {return this},
    configurable: true
    // 该属性的存在是确保该属性可被delete方法删除
});

var person = o.run('self');
delete Object.prototype.self;
//由于不推荐使用prototype来扩展自己定义的属性(扩展标准规定的除外),这里把扩展再去掉。

相较 小俞 的做法,这里面的用到的都是共有方法,不是__xxx__这种更为私有的方法(__xxx__)这种可能在不同浏览器里的实现不一样。

关注 48 回答 8

Abruzzi 赞了文章 · 2015-06-08

千位分隔符的完整攻略

千位分隔符[1]是很常见的需求,但是输入文本千变万化,如何才能准确添加千分符呢?

纯整数情况

![](/content/images/2015/06/integer.png)

纯整数大概是所有情况里最简单的一种,我们只要正确匹配出千分位就好了。

观察上面的数字,我们可以得出千分位的特征是到字符串终止位有 3n 个数字,不包括起始位。于是可以得到这样的函数:

javascriptlet milliFormat = (num) => {
    return num && num.toString().replace(/(?=(?!^)(\d{3})+$)/g, ',')
}

但是往往现实没有那么乐观:

小数的情况

float

遇到小数时,我们的希望只针对整数部分添加千分符,这时问题就变得稍稍有些棘手了。

如果正则引擎支持逆序环视[2],我们可以这样构造正则表达式:

javascript(?<=^\d+)(?=(\d{3})+\b)

但是多数语言并不支持逆序环视,所以我们要变通一下:

1. 拿到小数的整数部分

也就是起始位到小数点(非数字)之间的部分,可以这样实现:

javascript^\d+

2. 为整数部分添加千分符

这一步可以利用我们之前的实现,整合在一起如下:

javascriptlet milliFormat = (num) => {
    return num && num.toString()
        .replace(/^\d+/g, (m) => m.replace(/(?=(?!^)(\d{3})+$)/g, ','))
}

这个函数对整、小数都能正确处理:

result-1

但在实际中,我们还可能传入一个整、小数混合的字符串:

整、小数混合字符串

mixture

这时我们就不能继续用字符串起终点 ^$ 来判定边界了,如果改成单词边界 \b 会发生什么呢:

result-2

哦不!连小数部分也被添上千分符了!怎样才能避开小数部分?

重新审视我们捕获整数部分所用到的正则:

javascript\b\d+

\b 的界定是 (?<!\w)(?=\w)|(?<=\w)(?!\w)[3],所以小数点也被视为单词边界了!所以我们不应该用单词边界作为界定条件,重新看刚才的字符串 12345678 1234.5678,可以发现整数部分的起始点都有一个特征:要么位于字符串起点,要么跟在空白符后。基于这点我们修改捕获整数部分的正则如下:

javascript(^|\s)\d+

result-3

咦,多出来一个空白符?别着急,看看我们用来匹配千分位的正则:

javascript(?=(?!^)(\d{3})+$)

判断条件是非起点、到结尾有 3n 个数字的位置,现在为了去掉这多出来的一个空格,我们应将起始条件改成单词边界:

javascript(?=(?!\b)(\d{3})+$)

完整函数如下:

javascriptlet milliFormat = (input) => {
    return input && input.toString()
        .replace(/(^|\s)\d+/g, (m) => m.replace(/(?=(?!\b)(\d{3})+$)/g, ','))
}

result-4

酷炫!我们已经能自如应付各种数值的混合了!这是耳边幽幽飘来产品经理的声音:如果我传入含有非数字的字符串呢……

复杂字符串

complex

在上一个例子中,我们只判断了起始边界,于是 1234ww 中的数字部分也会被捕获。为了解决这个问题,我们要加上终止界定。来看看整、小数成立的条件:

字符串中仅包含有数字 0-9 或小数点

依据这个我们可以这样做:

javascript(^|\s)\d+(?=\.?\d*($|\s))

这个正则表示匹配目标应以字符串起始位或空白符开始,紧接着是数字,数字的右边只允许继续是数字或者一个小数点、直到字符串结尾或下一个空格处。来看看它的匹配效果:

result-5)

好样的!我们已经能精确匹配出正确的部分了!继续用之前的千分位模式封装:

javascriptlet milliFormat = (() => {
    const DIGIT_PATTERN = /(^|\s)\d+(?=\.?\d*($|\s))/g
    const MILLI_PATTERN = /(?=(?!\b)(\d{3})+$)/g

    return (input) => input && input.toString()
        .replace(DIGIT_PATTERN, (m) => m.replace(MILLI_PATTERN, ','))
})()

result-6

酷炫!全部都正确处理了!回家睡觉!

so-dick

更复杂的世界

@vc1指出,在现实中可能还会有更加复杂的情况,如:

'1234 1234.56 $1234 $-1234 $-1234.56e+7 123...e3'  

容我先去买根上吊绳……

(全文完)

参考资料

  1. 小數點 - 维基百科
  2. 正则基础之——环视 - 雁过无痕
  3. 正则基础之——\b 单词边界 - 雁过无痕

重编自我的博客,原文地址:https://idiotwu.me/milli-formatting-digitals-with-regex/

查看原文

赞 9 收藏 28 评论 9

Abruzzi 回答了问题 · 2015-06-04

前端的前景如何?是不是比后端研发前景差?

「朋友劝我说,前端你一两个月可以自学会,别人也可以。
还是学java比较有前途。」

--呵呵

关注 47 回答 39

Abruzzi 发布了文章 · 2015-05-21

CSS Stacking Context 里那些鲜为人知的坑

通常我们在学习/了解CSS的时候,并不会直接接触/了解到stacking context的规则,甚至在初学的时,仅仅接触到z-index、知道可以通过z-index控制元素显示的前后顺序,却常常由此碰到各式各样匪夷所思的bug,这两天我也趟了一次z-index浑水,搞明白了z-index扯出的这一系列stacking context坑。

什么是z-index

在W3C document里对z-index的解释是:

The z-index attribute lets you adjust the order of the layering of objects when rendering content.
It means that CSS style rules allow you to position boxes on layers in addition to the normal rendering layer (layer 0). The Z position of each layer is expressed as an integer representing the stacking order for rendering. Greater numbers mean closer to the observer.

简言之我们通过z-index在layer 0上控制「已定位」元素的先后顺序,其值越大元素越靠近用户。#这里layer 0指代root节点即html元素

什么是Stacking Context

显然仅仅知道z-index的作用并不能解释现实中诸多怪异的CSS z-index定位表现,如同上一节中提到指代root节点的layer 0,在CSS中也可构造出与其相似的结构,这种提供z-index栈空间特性并影响子元素渲染顺序的结构,我们称之为stacking context。

怎样的CSS属性可以使element形成一个Stacking Context

满足下面规则的元素将会构造出一个 Stacking Context 结构:

  • root元素(html)
  • 「已定位」元素(position: absolute or relative)且 指定z-index值非auto的元素
  • flex item且指定z-index值非auto的元素
  • opacity小于1的元素
  • 指定transform值非none的元素
  • 指定mix-blend-mode值非normal的元素
  • 指定filter值非none的元素
  • 指定isolation值为isolate的元素
  • ==特例 mobile webkit & chrome 22+, 指定position: fixed的元素==
  • 在will-change属性上指定值为上述列表任意属性的元素
  • 指定-webkit-overflow-scrolling值为touch的元素

*注意除了前两条之外有如此多满足创建stacking context的条件,这也是造成诸多bug的源泉,比如opacity<1

Stacking Context有什么特性

  1. stacking context可以嵌套
  2. 每个stacking context相对于兄弟元素是完全独立的,其内部规则不会影响到外部
  3. 每个stacking context元素都会被父stacking context当做一个元素施加stacking规则

对于一个stacking context内部的元素,如果这个元素没有形成stacking context,其z-index值是auto(但其实如果这个元素没有形成stacking context,z-index属性对这个元素的表现根本没有意义,我们可以理解为这个元素和其parent stacking context是一体的)。

我们通过给已定位元素(position: absolute or relative)指定z-index值以改变元素在其parent stacking context中Z轴的「相对偏移」量。这里的「相对偏移」指的是以parent stacking context为基准,相对于其它兄弟元素距离用户远近的顺序。

由于形成stacking context的元素其z-index属性并不对内部元素产生影响,因此其子元素以其(parent stacking context)为z-index相对基准点即z-index: auto,这些子元素的stacking context兄弟元素按照下面的远近顺序展示在屏幕:

远 ---------> 近
parent stacking context >> z-index < 0 >> 非stacking context元素(z-index: auto) >> z-index >= 0

*注意在stacking context中的元素不会远于parent stacking context

非「定位」元素Stacking Context的特殊规则

先上一段极其容易产生困惑的代码(不支持embedded scripts略卵疼):

See the Pen yNJRKX by abruzzi (@abruzzi) on CodePen.

<script async data-original="//assets.codepen.io/assets/embed/ei.js"></script>
http://codepen.io/abruzzi/pen/yNJRKX

如上文提及,这里box3和box5通过opacity: .99创建了一个stacking context,但box3却覆盖在了box4之上,翻查W3C文档并没有这样一条规则定义stacking context元素默认在非stacking context元素之上;我们修改了box5的z-index属性为负值,box5依然在box6之上;我们又通过position: relative & z-index: -1创建了box7的stacking context,其表现却是正常的(话说回来,z-index: auto本身也无法形成stacking context,因此根本没有存在类似「stacking context元素默认在非stacking context元素之上」定义的意义)

在W3C文档的某个角落,我们可以究其原委:

If an element with opacity less than 1 is not positioned, implementations must paint the layer it creates, within its parent stacking context, at the same stacking order that would be used if it were a positioned element with ‘z-index: 0’ and ‘opacity: 1’.

简言之,如果一个元素不是通过「定位」(position: absolute or relative)实现了stacking context,它将会以z-index: 0(高于auto)被看待,因此无论如何更改非「定位」元素的z-index都是无效的。

虽然文档中只提到opacity less 1构成的stacking context被看做z-index: 0,但通过测试,可以发现其他非「定位」方式创建的stacking context拥有与opacity less 1一致的表现。

以上便是我对CSS stacking context中造成诸多匪夷所思现象原因的总结。


*注:下文内容与题目无关,仅为作者思路延展

什么是GraphicLayer

浏览器在解析渲染document时,内部的处理并未直接暴露给我们,其中很重要的结构就是Layers。在这些未暴露的步骤中,RenderLayers负责渲染整个DOM子树结构,GraphicLayers则负责渲染RenderLayers中的子树,GraphicLayer把所负责的子树作为textures(可以理解为内存间移动的位图)upload到GPU,以实现高速绘制,也因而可以大幅优化这些属性带来的动画效果。

包括opacity在内,这些可产生stacking context的属性和创建特殊GraphicLayers的属性(opacity, filter, transfrom3d等)都很相似,但某些属性却又无法吻合(例如2d transfrom),冥冥之中总觉得两者原理上有相似之处,能力有限,只好留一坑。

Fixed定位脱离Viewport的bug

在定位中有一个跟stacking content无关但又较为相近的危险Bug,注意下面代码中.inner的定位:

See the Pen VLKeZP by abruzzi (@abruzzi) on CodePen.

<script async data-original="//assets.codepen.io/assets/embed/ei.js"></script>
http://codepen.io/abruzzi/pen/VLKeZP

对于声明transfrom值非none元素,其子元素中若存在position: fixed将以声明transform的最近祖先作为基准而定位,这是因为transfrom值非none的元素定义了一个局部坐标系统,导致postion: fixed以此坐标系统计算布局。
目前这个bug仍未被解决,官方建议避免在transform元素下做fixed定位。


by Abruzzi's blog

查看原文

赞 19 收藏 44 评论 5

Abruzzi 发布了文章 · 2015-05-21

Git push与pull的默认行为

一直以来对git pushgit pull命令的默认行为感觉混乱,今天抽空总结下。

git push

通常对于一个本地的新建分支,例如git checkout -b develop, 在develop分支commit了代码之后,如果直接执行git push命令,develop分支将不会被push到远程仓库(但此时git push操作有可能会推送一些代码到远程仓库,这取决于我们本地git config配置中的push.default默认行为,下文将会逐一详解)。

因此我们至少需要显式指定将要推送的分支名,例如git push origin develop,才能将本地新分支推送到远程仓库。

当我们通过显式指定分支名进行初次push操作后,本地有了新的commit,此时执行git push命令会有什么效果呢?

如果你未曾改动过git config中的push.default属性,根据我们使用的git不同版本(Git 2.0之前或之后),git push通常会有两种截然不同的行为:

  1. develop分支中本地新增的commit被push到远程仓库
  2. push失败,并收到git如下的警告
fatal: The current branch new has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin develop

为什么git版本不同会有两种不同的push行为?

因为在git的全局配置中,有一个push.default属性,其决定了git push操作的默认行为。在Git 2.0之前,这个属性的默认被设为'matching',2.0之后则被更改为了'simple'。

我们可以通过git version确定当前的git版本(如果小于2.0,更新是个更好的选择),通过git config --global push.default 'option'改变push.default的默认行为(或者也可直接编辑~/.gitconfig文件)。

push.default 有以下几个可选值:
nothing, current, upstream, simple, matching

其用途分别为:

  • nothing - push操作无效,除非显式指定远程分支,例如git push origin develop(我觉得。。。可以给那些不愿学git的同事配上此项)。

  • current - push当前分支到远程同名分支,如果远程同名分支不存在则自动创建同名分支。

  • upstream - push当前分支到它的upstream分支上(这一项其实用于经常从本地分支push/pull到同一远程仓库的情景,这种模式叫做central workflow)。

  • simple - simple和upstream是相似的,只有一点不同,simple必须保证本地分支和它的远程
    upstream分支同名,否则会拒绝push操作。

  • matching - push所有本地和远程两端都存在的同名分支。

因此如果我们使用了git2.0之前的版本,push.default = matching,git push后则会推送当前分支代码到远程分支,而2.0之后,push.default = simple,如果没有指定当前分支的upstream分支,就会收到上文的fatal提示。

upstream & downstream

说到这里,需要解释一下git中的upstream到底是什么

git中存在upstream和downstream,简言之,当我们把仓库A中某分支x的代码push到仓库B分支y,此时仓库B的这个分支y就叫做A中x分支的upstream,而x则被称作y的downstream,这是一个相对关系,每一个本地分支都相对地可以有一个远程的upstream分支(注意这个upstream分支可以不同名,但通常我们都会使用同名分支作为upstream)。

初次提交本地分支,例如git push origin develop操作,并不会定义当前本地分支的upstream分支,我们可以通过git push --set-upstream origin develop,关联本地develop分支的upstream分支,另一个更为简洁的方式是初次push时,加入-u参数,例如git push -u origin develop,这个操作在push的同时会指定当前分支的upstream。

注意push.default = current可以在远程同名分支不存在的情况下自动创建同名分支,有些时候这也是个极其方便的模式,比如初次push你可以直接输入 git push 而不必显示指定远程分支。

git pull

弄清楚git push的默认行为后,再来看看git pull

当我们未指定当前分支的upstream时,通常git pull操作会得到如下的提示:

There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details

    git pull <remote> <branch>

If you wish to set tracking information for this branch you can do so with:

    git branch --set-upstream-to=origin/<branch> new1

git pull的默认行为和git push完全不同。当我们执行git pull的时候,实际上是做了git fetch + git merge操作,fetch操作将会更新本地仓库的remote tracking,也就是refs/remotes中的代码,并不会对refs/heads中本地当前的代码造成影响。

当我们进行pull的第二个行为merge时,对git来说,如果我们没有设定当前分支的upstream,它并不知道我们要合并哪个分支到当前分支,所以我们需要通过下面的代码指定当前分支的upstream:

git branch --set-upstream-to=origin/<branch> develop
// 或者git push --set-upstream origin develop 

实际上,如果我们没有指定upstream,git在merge时会访问git config中当前分支(develop)merge的默认配置,我们可以通过配置下面的内容指定某个分支的默认merge操作

[branch "develop"]
    remote = origin
    merge = refs/heads/develop // [1]为什么不是refs/remotes/develop?

或者通过command-line直接设置:

git config branch.develop.merge refs/heads/develop

这样当我们在develop分支git pull时,如果没有指定upstream分支,git将根据我们的config文件去merge origin/develop;如果指定了upstream分支,则会忽略config中的merge默认配置。

以上就是git push和git pull操作的全部默认行为,如有错误,欢迎斧正


[1] 为什么merge = refs/heads/develop 而不是refs/remotes/develop?
因为这里merge指代的是我们想要merge的远程分支,是remote上的refs/heads/develop,文中即是origin上的refs/heads/develop,这和我们在本地直接执行git merge是不同的(本地执行git merge origin/develop则是直接merge refs/remotes/develop)。

refs:
http://git-scm.com/book/en/v2/Git-Internals-The-Refspec
http://stackoverflow.com/questions/658885/how-do-you-get-git-to-always...
http://stackoverflow.com/questions/17096311/why-do-i-need-to-explicitl...
http://www.gitguys.com/topics/the-configuration-file-branch-section/

by Abruzzi's blog

查看原文

赞 39 收藏 110 评论 8

Abruzzi 发布了文章 · 2015-05-21

如何理解 koa 中间件执行机制

前几天研究了TJ的koa/co4.x和一系列koa依赖的源码,在知乎上做出了人生首次回答(而且我真得再也不想去知乎回答技术问题了_(:з」∠)_),因此把文字搬到这里。

ES2015 Generator/Yield

关于Generator/Yield 这几篇文章已经写得足够清晰了:

Koa的运行机制

简单地画了一张图解释koa的处理流程:

图片描述

在koa里定义的middleware均为generator function(包括内置在顶端的respond),这是为了能从任意middleware中容易地切换到其它middleware里(如果你是前端程序员,可以理解为浏览器捕获事件的capture和propagation过程,如果你是python程序员,可以理解为jungle的middleware机制,如果你是Java程序员,这种方式则是典型的切面编程)。

为了实现这种横穿多个middleware的特性,koa通过把后一个generator作为参数(koa里常用next)传入前一个generator实现(#见koa-compose源码,这也是为什么前两个middleware有next参数而最后一个没有)。

可以看到,在koa中yield的使用是在co,而co则是包装了generator/yield & Promise以模拟async/await,提供了一个更高层次的异步语法抽象。

koa在加载且合并所有的middleware之后,传递给co执行(确切地说是在http.createServer的callback触发后执行),co以图中所示逻辑不断拆解generator function,执行yield右侧固定的几种表达式(Array,Object,generator function,Promise,thunkify function),这5种表达式最终都会转化为Promise,以达到处理异步函数的目的。

co内部封装了onFulfilled和onRejected函数,当yield右侧的promise resolve之后,则会调用onFullfield函数,其包含了一条关键语句gen.next(res)#这句代码 用以给yield表达式赋值并执行下一次迭代。

koa通过上文的方式「深入」->「浅出」,最终在顶层的respond middleware里send response。

注:#thunk是co先前版本处理异步函数的方式,通过thunk可以将异步函数封装成curry,传入普通参数后形成仅需要callback参数的偏函数,以此简化callback调用代码(目前co中的thunk偏函数已经被#无情地Promise化了)。

by Abruzzi's blog

查看原文

赞 4 收藏 21 评论 1

认证与成就

  • 获得 63 次点赞
  • 获得 0 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 0 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2015-05-21
个人主页被 687 人浏览