-
Notifications
You must be signed in to change notification settings - Fork 0
/
content.json
1 lines (1 loc) · 104 KB
/
content.json
1
[{"title":"正则表达式学习笔记","date":"2017-08-27T14:22:05.000Z","path":"27/08/learn-regexp1/","text":"正则表达式 RegExp 目录 1. 介绍 2. 语法 3. 高级语法 4. 使用 1. 介绍 正则表达式,又称正规表示式、正规表示法、正规表达式、规则表达式、常规表示法(英语:Regular Expression,在代码中常简写为regex、regexp或RE),是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些匹配某个模式的文本。 正则表达式不是js、java或者其他某一种计算机语言特有,而是不同语言中都有,例如Python、php、Ruby、C++……,是用来处理文本的一种特定语法规则。 2. 语法2.1 元字符 元字符 描述 . 句号匹配任意单个字符,除了换行符 [ ] 字符种类. 匹配方括号内的任意字符 [^ ] 否定的字符种类. 匹配除了方括号内的任意字符 * 匹配>=0个重复在*号前的字符 + 匹配>=1个+号前的字符 {n, m} n是min最小数量,m为max为最大数量,匹配这个区间个数的中括号前的字符 ? 标记?之前的字符为可选; 等价于 {0,1}。 (xyz) 字符集,匹配与xyz完全相等的字符 模式 /(foo) (bar) \\1 \\2/ 中的 ‘(foo)’ 和 ‘(bar)’ 匹配并记住字符串 “foo bar foo bar” 中前两个单词。模式中的 \\1 和 \\2 匹配字符串的后两个单词。注意 \\1、\\2、\\n 是用在正则表达式的匹配环节。在正则表达式的替换环节,则要使用像 $1、$2、$n 这样的语法 ,例如,’bar foo’.replace( /(…) (…)/, ‘$2 $1’ )。 3. 1 replace 多参数匹配 \ 转义字符,用于匹配一些保留的字符 [ ] ( ) { } . * + ? ^ $ \\ | ^ 匹配输入的开始。如果多行标志被设置为true,那么也匹配换行符后紧跟的位置。例如,/^A/ 并不会匹配 “an A” 中的 ‘A’,但是会匹配 “An E” 中的 ‘A’。当 ‘^’ 作为第一个字符出现在一个字符集合模式时,它将会有不同的含义 $ 匹配输入的结束。如果多行标示被设置为true,那么也匹配换行符前的位置。例如,/t$/ 并不会匹配 “eater” 中的 ‘t’,但是会匹配 “eat” 中的 ‘t’。 2.2 字符集 简写 描述 \\w 匹配一个单字字符:数字、字幕或下滑线; 等价月[A-Za-z0-9_] \\W 匹配非单字字符,等价于[^A-Za-z0-9_] \\d 匹配一个数字,等价于[0-9] \\D 匹配一个非数字字符,等价于[^0-9] \\s 匹配一个空白字符, 包括空格、制表符、换页符和换行符 \\S 匹配一个非空白字符。 \\f 匹配一个换页符 \\n 匹配一个换行符 \\r 匹配一个回车符 \\t 匹配一个水平制表符 \\v 匹配一个垂直制表符 \\p 匹配 CR/LF (等同于 \\r\\n),用来匹配 DOS 行终止符 2.3 修饰符正则表达式的修饰符,修饰符放在’/‘符号之外,JavaScript支持三个修饰符 字符 描述 i 执行不区分大小写的匹配 g 执行一个全局的匹配;查找所有的匹配,而不是找到第一个之后就停止 m 多行匹配;例如:/java$/im 可以匹配’java’, 也可以匹配“java\\nis fun” 3. 高级语法3.1 replace 多参数匹配1234567function replacer(match, p1, p2, p3, offset, string) { // p1 is nondigits, p2 digits, and p3 non-alphanumerics return [p1, p2, p3].join(' - ');}var newString = 'abc12345#$*%'.replace(/([^\\d]*)(\\d*)([^\\w]*)/, replacer);// 输出结果:// abc - 12345 - #$*% 零宽断言 用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言 (?=exp) 也叫零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp。 例如:/[Jj]ava([Ss]cript)?(?=\\:)/ 可以匹配”JavaScript: The Definitive Guide” 中的 “JavaScript”;但是不能匹配”Java in a Nutshell” 中的 “Java”,因为没有匹配断言中的“:” 负向零宽断言 零宽断言的相反,指定位置不包含满足条件的;(?! exp) 12345var reg = /Java(?!Script)([A-Z\\w*]+)/g; // 匹配Java后面没跟有"Script"var str = "a JavaScript Javaas";str.match(reg); // 返回 ["Javaas"] 贪婪与懒惰4. 使用4.1 正则在js中的使用正则在JavaScript里面的使用,有两种形式: +. 一种是RegExp() 的exec() 和 test()+. 一种是String的match、split、replace、search RegExp正则表达式也是JavaScript对象。RegExp() 构造函数带有两个参数,第一个参数是正则表达式的直接量,也就是两条斜线中间的文本,但是转义字符需要单斜线改为双斜线:'\\' --> '\\\\';第二个参数是可选的,也就是正则表达式的修饰符,也就是上面提到的g、i、m12345例子: let regexp1 = new RegExp('ab+c'); let regexp2 = new RegExp('\\\\d{5}', 'g'); let regexp3 = new RegExp(/^[a-zA-Z]+[0-9]*\\W+_$/, "gi"); // 匹配'abc123*_' let regexp4 = new RegExp("^[a-zA-Z]+[0-9]*\\W+_$", "gi"); // 这个正则其实和上面的例子其实是不相等的,需要将\\W+ 改为 \\\\W+ test() 用法: 参数是字符串,结果返回boolean,如果符合正则表达式则返回true123let regexp1 = new RegExp('ab+c');regexp1.test('abbc'); // falseregexp1.test('abbc'); // true exec() 用法: regexObj.exec(str) 匹配失败返回null、匹配成功返回一个数组 这是个比较稍微难理解的使用方法,但是使用确实很频繁,因为实用。首先,匹配失败返回null,成功是返回的是一个数组类型其次,既然是数组,那肯定可能就有多个结果; 数组的第一位,是与正则表达式相匹配的字符串; 数组的第二位和之后的,是正则表达式”( )”中相匹配的; 123456var re = /quick\\s(brown).+?(jumps)/ig;var result = re.exec('The Quick Brown Fox Jumps Over The Lazy Dog');console.log(result)// console: ["Quick Brown Fox Jumps", "Brown", "Jumps"]// 数组第一位是正则匹配,第二位 和第三位 对应正则里的两个”()“ 很常见到exec会在while循环里使用;当正则表达式使用 “g” 标志时,可以多次执行 exec 方法来查找同一个字符串中的成功匹配。当你这样做时,查找将从正则表达式的 lastIndex 属性指定的位置开始。 123456789101112var myRe = /ab*/g;var str = 'abbcdefabh';var myArray;while ((myArray = myRe.exec(str)) !== null) { var msg = '匹配到的数据是 -> ' + myArray[0] + '. '; msg += '| 下一次匹配位置 -> ' + myRe.lastIndex; console.log(msg);}// console 打印:// 匹配到的数据是 -> abb. | 下一次匹配位置 -> 3// 匹配到的数据是 -> ab. | 下一次匹配位置 -> 9 String search() 参数是正则表达式,返回一个素质,找不到返回-1,找到返回匹配的起始位置; 如果参数不是正则表达式,会RegExp构造函数转换成正则表达式。不支持全局搜索,忽略正则表达式上的修饰符g; 123"JavaScript".search('/vaS/i');// 结果 return 2; replace(), 两个参数,第一个正则表达式,第二个是需要替换的字符。如果第一个参数是字符串不是正则表达式,replace不会将字符串转化为RegExp(),而是直接搜索该字符串,如果不是g 全局匹配,replace只会替换第一个匹配的。 1234567891011121314基本用法:"javascript is the best language".replace(/javascript/gi, "JavaScript");高级用法:var a = "\\"bich\\" go die"// $1 代表子表达式(exp)匹配的字符// 将bich保存在$1中 不被修改var b = a.replace(/"([^"]*)"/, '“$1”'); console.log(b)// console结果:中文半角引号替换英文引号,引号内容不变 // “bich” go die split() 123var text = "1, 2, 3, 4"var result = text.split(/\\s*,\\s*/); // 去除空格console.log(result) // 返回["1","2","3","4"] match() 参数为正则表达,如果是字符串也会转成RegExp()对象,返回是数组类型,包含所有匹配的结果,如果没有设置全局搜索的修饰符g,只会返回只包含第一个匹配的数组; 1234567891011121314151617//一个具有字表达的match例子var url = /(\\w+):\\/\\/([\\w.]+)\\/(\\S*)/;var URLText = 'Visit my blog http://lixingdecai.com/home'var result = URLText.match(url)if(result != null) { console.log(result[0]); // 第一个位置存储完整的匹配结果 console.log(result[1]); // 存放第一个子表达式匹配的结果 console.log(result[2]); // 存放第二个子表达式 也就是(exp)匹配的,后面以此类推 console.log(result[3]);}// console结果// http://lixingdecai.com/home// http// lixingdecai.com// home 4.2 正则表达式的应用场景 web 表单校验 我们前端工程师非常熟悉的表单校验,要校验是否输入纯数字、合法身份证、合法手机号等等、 CSS 选择器引擎 几乎所有的 CSS 选择器引擎会使用正则表达式。jQuery 所使用的选择器引擎 Sizzle.js 使用了大量的正则表达式以匹配各式各样的 CSS 选择器。 爬虫 你要从一网页中截取有效信息,大部分爬虫都是使用正则表达式去匹配提取需要的信息 编译器 在高级点使用,如编译器,大部分编译型编程语言设计的程序在执行之前要经历三个步骤: +. 分词/词法分析+. 语法分析,生成抽象语法树(AST)+. 翻译为字节码/机器码 JS 正在表达式 MDN learn-regex","tags":[{"name":"javaScript","slug":"javaScript","permalink":"http://www.lixingdecai.com/tags/javaScript/"},{"name":"对象","slug":"对象","permalink":"http://www.lixingdecai.com/tags/对象/"}]},{"title":"美柚RN前端框架演进","date":"2017-07-02T13:22:05.000Z","path":"02/07/share_react_native/","text":"美柚其实在具有热更新功能的混合应用技术运用中算比较晚了,经过一系列的调研准备,于今年的3月份,开始在美柚APP上使用RN框架(去年9月,有在杭州电商里面使用了几个RN的页面,但只是粗略应用)。因为大家都没有什么经验,基本都是摸着石头过河进行尝试。这篇文章就是用来记录基于美柚APP的RN框架从0到1的一个开发和设计的过程。 台前幕后痛点:在做这个事情前,我们先要明确我们要做这个事情的原因和目的,我们为什么要这么做。 开发维护成本太高:要开发维护两套代码,而且原生在开发用户界面上的成本非常高,我之前写android页面你写个样式的编写维护好几个xml文件,不同的列表数据还得写不同类型的适配器。开发维护成本比web的页面开发高很多。 繁复的版本管理:新老版本都要做兼容,就会出现一系列的版本。 频繁的变更需求:在ios下,新版本发布需要通过app store的提交审核,会有个时间的延迟。不具备热更新的功能。 性能体验的保证:在H5下的性能和体验得不到保证。 App size越来越大:目前美柚App已经快97MB,柚宝宝已经107MB。 定位要清楚RN的定位,RN是一种解决方法,他是为了解决以上那些痛点而存在的。也就是在对比Native 和 H5, 要清楚RN 的优势在哪里。我们也要清楚认识到,在移动端App上,native 和 H5都是有其存在的价值的,RN可以替代他们,但是目前是不可能完全取代的。 横向对比知道为什么做、知道哪些痛点和要做这件事件的目的。现在就要知道怎么去做,用什么方式和方法。在市面上,流行的框架有 ionic nativescript weex reactnative四种比较主流的框架。这四个框架都是可以解决上面提到的那些痛点。 对于这些技术,我们提前做了下调研。 Ionic Ionic is the beautiful, free and open source mobile SDK for developing native and progressive web apps with ease. 就算你不懂任何移动端技术,也是可以hold的住的框架。在之前,我有落地过一个INOIC 1的项目,开发体验非常好,上手速度也非常快。INONIC1是基于ng1, IONIC2 是基于ng2。纯前端的开发模式,对前端开发人员的门槛很低,学习成本也很低。他是基于webview进行开发的APP,使用cordova API调用原生的功能。而且极光JPush之类的第三方插件都对IONIC支持,生态链也非常成熟。 但是唯一的缺陷,也是致命的缺陷就是性能和体验的问题。目前出的IONIC2听说性能有很大改进,但是肯定没办法跟原生的相比。IONIC比较适合于一下小型的APP,和能力有限并且要快速迭代的初创公司。 网上对ionic的评价:12345678优势: ios 和 android 基本上可以共用代码,纯web思维,开发速度快,简单方便,一次编码,到处运行,如果熟悉web开发,则开发难度较低。 文档很全,系统级支持封装较好,所有UI组件都是有html模拟,可以统一使用。 可实现在线更新 允许加载动态加载web js 前端的程序员就可以独立开发 文档多,开发者多,视频教程多 容易学习 遇到问题容易解决 技术成熟劣势: 占用内存高一些(不过手机内存都大了不影响),不适合做游戏类型app, web技术无法解决一切问题,对于比较耗性能的地方无法利用native的思维实现优势互补,如高体验的交互,动画等。 Nativescript cross-platform mobile applications 出现的很早,比RN还出现的更早一点。和RN与weex一样,都是最终转为native的解决方案,出自于一个保加利亞的軟件公司公司Telerik,比RN还出现的略早点,版本已经到了3.1。也是native、也是有各种组件、支持各种css style、也可以chrome调试开发,也支持集成进native的混合开发。很无解它的短板在什么地方,为什么用的人不多,网络上的相关资料也很少。看到的为数不多的文章写有偏向于整体的解决方案,网上更多的评论是NS更注重于用户体验功能之类的,而对于UI渲染这块是比较弱,不置可否。大部分来自ionic的开发者,因为可以不用去关注native的相关技术。原生的开发应用性能得到保障。但是相关文档比较少,大部分都得通过官网学习,NS的中文网站都还没翻译全。关于NS的文章也是很少,基本都得看外文文献NS vs RN 其实我对NS没有过多实践,所有知道都是从官网或者其他的人写的文章这样的第二手资料,没什么资格去说这个事情,上面的评论大家看看就好。 传送门NativeScript 10K 文档 WEEX: Write once, Run anywhere! weex 14k 原理:Weex 表面上是一个客户端技术,但实际上它串联起了从本地开发环境到云端部署和分发的整个链路。开发者首先可以在本地像撰写 web 页面一样撰写一个 app 的页面,然后编译成一段 JavaScript 代码,形成 Weex 的一个 JS bundle;在云端,开发者可以把生成的 JS bundle 部署上去,然后通过网络请求或预下发的方式传递到用户的移动应用客户端;在移动应用客户端里,WeexSDK 会准备好一个 JavaScript 引擎,并且在用户打开一个 Weex 页面时执行相应的 JS bundle,并在执行过程中产生各种命令发送到 native 端进行的界面渲染或数据存储、网络通信、调用设备功能、用户交互响应等移动应用的场景实践;同时,如果用户没有安装移动应用,他仍然可以在浏览器里打开一个相同的 web 页面,这个页面是使用相同的页面源代码,通过浏览器里的 JavaScript 引擎运行起来的。 其实最开始选型的第一选是weex,选择他原因有三吧 基于vue,我们刚做完一个vue的项目,开发体验很不错 可以三端统一,不只是 IOS和 Android,还有 H5也是可以,由于它的代码是基于VUE的,在IOS和android只是集成了sdk进行转换。 对国产的支持吧 从选用开发,到弃用,归结起来的原因有以下几点吧: 生态链欠成熟;pull request 没有响应,论坛的提问也是过两天自己回答。 文档不全;刚好也碰到weex官方支持vue,在官方文档也在升级支持vue,然后我们刚好是使用的最新支持vue开发的版本。官放说明文档很不全,得新老切换这看。 团队对阿里开源的畏惧;好像都吃过阿里开源项目的亏,阿里KPI项目的尿性也是众人皆知了。又值阿里将weex贡献给apache时间节点,心里怕怕的。 能力不够;怕自己hold不住;其实最关键还是我们能力的问题,我们没有那么多时间、精力、人力耗在这个上面。不希望这个月绩效为0分; 页面效果不理想;我们拿贴士的页面入手,但是出来的效果,在IOS上显示差异很大。 react native 优点 目的 基于 React 前端的技术栈,组件化开发思想 相对于 native,开发速度快,成本低 相对于 H5,性能更优异,体验更好 生态比较成熟,社区活跃,市场成熟,开源组件丰富充足 RN在市场中的使用情况(图片中数据来源于携程2016.10统计的android市场的数据) Learn once,Write anywhere! RN 50K做不到 Write once, Run anywhere! 对于一些特定的组件,还是要写两套代码。 落地狂奔快速迭代因为从weex半路转到RN,所以基本是从零开始。对很多东西都疑惑: 怎么将RN集成进美柚App RN 和native 怎么进行交互传值 \b页面跳转;native 怎么跳 RN页面,RN页面怎么跳RN 页面。 如何开发编译完的bundl文件给Native。 ReactNative是基于react,而我只是对react\b有理论知识上的了解,还没有落地过任何项目。但是经过一个月的小步快跑。完成了八个页面的改造,18个组件的抽象,还有和native协定了交互的规范。 人员配置不管是RN 或者weex 都不是真的像他们的宣传语一样,学一次或者写一次就能在任何地方使用,也不可能只由一个\b程序员完成。你得会客户端的语言,不管你是写独立的RN APP或者是像我们集成native中的APP。对于大部分公司的程序员,基本是不可能写ios、android和前端三端代码,至少现在还没\b遇到过。比较多的是,android客服端的同学学习react或者vue, ios 客户端的同学学习前端的语言。js是个脚本语言,相对门槛还是比较小的。而前端同学如果之前没有基础积累,再去学习客户端,不管是android 或者ios,难度都是非常大的。 所以这\b需要一个团队来共同完成,以下是我们的人员配置: 其实在开发过程中,会碰到很多分歧,\b当谁也无法说服谁的时候,就得找江大了,江大做定夺。 在开发联调\b过程中,如果是涉及到协议、规范、结构之类的通用部分,我们会一起协商。但是对于可行性研究,前端不可能同时和IOS、android两端同时进行,我们会选择一端进行,如果通过了才会再在另一端开发。我选择的是IOS,xcode运行内存占比只有几百MB,ASD内存占用就达到2G左右。在mac上启动xcode或者模拟器也会很快。如果是开发,你用Android 真机或者ios 真机就都差不多了,因为不用设计底层开发造成的模拟器频繁代码更新。 成果展示Android的数据统计来自宏弘的\b统计数据 从以上数据来看,RN的整体速度比WebView快了1倍,启动速度会比WebView稍微慢点,原因在于RN的启动需要解析bundle文件,需要耗时。Eatable页面,WebView比RN要快,这块主要是启动时间慢导致,可能原因是bundle文件过大导致解析慢。 IOS效果对比RN底下访问静态页面基本是秒开秒关 H5\b有时候点击了要一段时间才有响应,页面加载速度也会慢一点。 在\b\b长数据列表页,或者picker选择器等上,原生体验秒杀H5 流程图在框架搭建设计中,得先确定整体的一个流程。当你对整流程有了清晰的认知,对你开发是有很大帮助的。 开发发布流程: 编译打包 通过RN提供的命令,先生成bundle文件 再将编译后的文件进行拆包,根据基础和业务进行拆包,各个依赖的资源文件进行拆封。 压缩;混淆压缩代码。减小代码量 打包:并根据不同环境不同版本进行分别打成zip包 上传CDN 将文件托管于CDN上,更好的请求加载速度 服务端配置 将上传CDN的地址,配置在服务器上。由相关的权限控制人员在后台服务上配置启停相关RN版本包。 权限管控:开发 和 生产隔离,开发环境上使用的版本由相对应的人员在服务端配置。权限隔离的好处,有助于问题排查,就是责任隔离。 解析RN 目前的\bRN的存在,是作为一个替代H5的方案,也就是只有在使用小工具\b这块中使用。native不管 H5或者 RN都是通过协议去调用唤醒的,所以会先进行一个判断,当使用RN协议并且RN页面存在,就打开RN页面。否则会跳转到H5页面。 渲染原理RN的编译过程,会将我们页面的React.createElement 来构建应用 UI,最终在render方法返回的都是元组件(view、image、picker等)。 当我们的页面要在客户端显示,会先在页面的contrller层(android底下是activity类),要new一个View对象。对应的是IOS的RCTRootView.m,android的ReactRootView.java。如果你没学过IOS 和android不要紧,可以理解为是个dom节点。一个页面可以由一个VIEW构成,也可以由多个VIEW构成。所以RN可以是一个页面,也可以是页面中的一小块。比如我们的广告项目在首页的插入就是用RN实现的。在新建view对象时,我们会调用\b一个\b引擎类,ios的RCTBridge.m 和android 的ReactInstanceManage.java类,去创建一个jscontext,去加载运行bundle文件。 交互在初始化的过程中会传递参数 RN 和 Native之间的交互,都是通过Native端提供的MeiyouRNBridge。\b 通信协议/网络请求协议的使用 或者网络请求,都是通过RN协议桥 MeiyouRNBridge来实现。 例如:MeiyouRNBridge.showToast(‘请求成功’);MeiyouRNBridge.setTitle(‘测试title’); 对与网络请求和协议的页面跳转,都在底层进行了相关封装。 比如下面的RN页面的跳转,你只需要在意模块的路径,名称,页面标题等相关参数,不用在意页面跳转的类型和这些传输的数据结构。 12345678910111213141516/** * 跳转RN 页面 * @param {string} source 模块路径 * @param {string} module 模块名称 * @param {string} title 页面标题 * @param {object} param 参数 * @param {*} info 信息 */const goRNPage = (source, moduleName, title, param, info) => { let params = {}; params.source = source; params.moduleName = moduleName; params.title = title; params.params = param; return runAction('reactnative', params, info);} 具体可以参考地址:http://git.meiyou.im/iOS/iOS/wikis/work/RN.md 网络请求使用native提供的封装的请求方法,而不使用RN提供的方法fetch,native会去请求方法做一些处理。比如拼接系统参数,比如根据所处的环境,比如测试、开发,自动切换不同的地址。 异常处理异常有很多种,网络异常,请求异常,解析异常等等,这些都属于逻辑层面的,是我们开发人员关心的。在业务层面只展示一种结果,小柚子找不到了。 所以相关就很好处理了。 一种写异常组件:Exception.js 一种是调用native提供的组件:MeiyouRNBridge.setLoadingState(3); 第一种是可以自己控制范围的,更灵活,例如你有个搜索框和列表,当你按条件搜索时候,出现超时等网络异常,你只要在展示部分显示异常,而不用全页面。第二种是更方便,但通用性差,只要调用提供的桥方法,就能全局覆盖。 白屏处理在native调用RN页面的时候,如果没下载会下载,还会有解析和渲染的过程,所以会出现个loading动画。在早之前,native 在启动加载RN页面后,会隐藏加载动画,杭州的电商那边就是这么做的。但是这其中有个问题,页面的渲染中包含些异步操作,会有一小段时间,也就是在加载动作结束后,会有一小段白屏或者闪屏出现,这个体验就不好了。为了解决体验问题,只能牺牲开发一些原则。native提供了关闭加载动画的方法,由我们自行控制结束动画。 工程化高效 可维护性。对于环境进行配置,一键命令式的完成编译,解析,拆包,拆分资源文件,压缩混淆,打包,清楚缓存等工作。 是否有必要使用云打包,我们只要合并代码进master分支,就会自动触发。 开发集成矢量小图标Fontawsome 对于Android 和 IOS,都提供了相对应的集成了美柚基本组件库的开发demo, 可以提供给前端开发,调试,基本可以还原美柚经期App的开发场景。 androidandroid 的开发demo如下图,开启调试模式功能 IOSIOS 的开发demo如下图 代码调试在模拟器或者真心打开上面的开发demo, android在进入页面后点击标题,ios在电脑模拟器上可以使用快捷键command + d,真机使用手机摇一摇,调出debug页面。有开启调试模式、热更新等等功能,如下图所示 然后再在浏览器输入 http://localhost:8081/debugger-ui 可以打断点跟踪,打印日志和平常web开发调试一样,如下图所示: 只是在页面跳转的时候,使用断点监听会红屏警告,只要点击dismiss就可以跳过去,但是会很影响调试。建议测试页面跳转之类的,在跳转到相关页面再打开调试模式。 永无止境优化1、如图所示,JS init+Require,这块时间也就是JSBundle的执行时间,这块耗时是最长的2、bundle文件随业务代码的增加是越来越大,如果每次更新,那耗费的流量会很大。怎么去缩减bundle文件的大小。 拆包拆包的原理:解析 拆包策略: 按照RN的基础部分 和 业务部分。我们拿一个空的RN包进行打包就能看到,一个bundle包的大小是1.7MB, 打包以后的zip包是400kb左右。而RN这个部分的基础包,只有更新RN版本的时候才会进行更新,而RN版本的更新是不向上兼容的,我们在从0.41升级到0.43的时候,就花了很多时间精力。不仅是前端,android 和ios也是一样的。所以这个部分没有特别的需求或者问题,不会变动。而经过拆包后。基础包208kb, 业务包237kb。解析前index.bundle.js是889kb, 解析后的base.bundle是779kb, 业务index.bundle 是284kb。 怎么使用: 一种是在客户端进行\b物理合并,将bundle文件拼接在一起,讲资源文件放在统一在同一个文件夹下。但是这样做,除了减少网络开销,不会有其他优化的好处,意义不大。所以放弃了。 另一种是让基础部分和业务部分在同一个作用域中运行。 数据缓存对网络请求的方法增加了本地缓存的功能。减少网络请求,加快了网页的响应速度。 对网络请求的方法进行封装改造,只要配置个属性标志是否需要缓存。如果这个接口是需要缓存的,我会优先读取本地的存储数据,再异步去请求数据,刷新本地的存储数据。这对很多变更性不大的页面会非常大的作用。类似能不能吃的index页面。极大的提高了打开RN页面的时间。 图片优化图片在页面中的比重占比非常大,图片的加载速度直接影响页面的加载渲染效果,所以对于图片的优化也是很重的。 针对图片的优化,目前从图片的尺寸 和 动态转换webp两方面进行优化。 关于webp:WebP 格式是 Google 于2010年发布的一种支持有损压缩和无损压缩的图片文件格式,派生自图像编码格式 VP8。 webp的优势:无损压缩后的 WebP 比 PNG 文件少了 45% 的文件大小,即使 PNG 文件经过其他压缩工具压缩后,WebP 还是可以减少 28% 的文件大小。此外,与 JPEG 相比,在质量相同的情况下,WebP 格式图像的体积要比 JPEG 格式图像小 40%,而 WebP 在压缩方面比 JPEG 格式更优越。 美柚客户端已经支持webp格式的图片显示,前端针对webp的这种图片格式进行了优化,针对美柚前端大多数图片都是来自于七牛,做了转码动态的支持。 并设置最大长宽来进一步限制图片大小,对图片裁剪为最大显示的两倍的尺寸。保证清晰度的前提下,优化了图片的大小。 使用说明:使用封装的MImge组件,可配置needWebp 和设置size大小。 1<MImage style={styles.themeIcon} size={[68,68]} needWebp={true} source={{uri: item.icon}}></MImage> 效果: 待优化 版本控制 如果开发人员在CDN上上传\u001d了新版本1.2,在服务器上配置的新地址。客户端的更新机制是,对比版本异同进行更新,原先版本在客户端有缓存,但是针对未及时打开app更新的情况下,如果原地址文件被覆盖更改,就会出问题。 性能优化:可优化空间,具体等上线以后的数据统计报告 自动化流程 拆包:commonjs的加载模式,所有的加载运行到内存中,AMD的异步按需加载方式 文档不全;开发规范,操作指南之类的。 CDN文件被破坏风险 安全性优化,对 bundle file MD5,进行 RSA 验证 框架抽离;可以复用多个项目,单独维护。 (感谢江大,盛华,宏弘的技术支持)","tags":[{"name":"javaScript","slug":"javaScript","permalink":"http://www.lixingdecai.com/tags/javaScript/"}]},{"title":"关于对象的声明 定义 引用 赋值 传递","date":"2017-04-27T13:22:05.000Z","path":"27/04/about-reference/","text":"声明、定义、引用、赋值这几个名词经常出现 应该都很熟悉,但放在一起,你们会知道这其中的差别吗。 申明申明:声明语句是本身什么也没有实现,只是通过创建变量和函数。查找栈内存,如果不存在创建的对象,则创建,并指向undefined。var、function、let、const都是声明语句,var 和 let 是用来申明变量的,只是let是es6新增的命令。function 是用来定义函数的。const 是用来申明常量的。 1234567891011121314151617181920let 和 var 的区别------ let --------var a = [];for (var i = 0; i < 10; i++){ a[i] = function () { console.log(i); }}a[6](); // 10------ var -------var a = [];for (let i = 0; i < 10; i++) { a[i] = function() { console.log(i); }}a[6](); // 6 定义函数的定义和函数的声明 函数的定义表达式1var square = function (x) { return x * x; } 函数申明语句的语法123456789function functionName ([args1,[args2,[..., argsn]]]) { statements;}例子:function factorial(n) { if (n <= 1) return n; return n * factorial(n-1);} 关于对象的引用赋值引用赋值看起来好像很简单,但是背后还是有些东西不搞明白,还是很容易搞糊涂的。比如你先得弄清楚对象的内存的堆栈是怎么存储的。这很关键。 原始类型:number、string、boolean、null、undefined 对象类型:属性集合、函数、数组、日期、正则、error 原始值是不可变得123var a = 'hello' // 定义一个由小写a.toSuperCase(); // 返回 HELLOs // s 还是 hello 通常将对象称为引用类型 (reference type), 对象的值都是引用,对象的比较都是引用的比较。 可变的对象引用 123456var a = []; // | —---堆----- | | ----栈---- |var b = a; // | a |-->| [] |b[0] = 1; // | b指向a的引用 | | |a[0] // | a| | |a === b 变量的声明var a;var a = 0, b = 0; 12345678910var scope = 'global';function () { console.log(scope); var scope = 'local'; console.log(scope);}// 输出// undefined 变量提升,块级作用域变量覆盖全局作用域同名变量// local、、、 es5 和es 6中变量提升的区别: es5的var 中存在变量提升,可以在变量声明前使用;es6的const、let两种命令不存在变量提升,不能再变量声明前使用变量; 传递按值传递123456789101112function a(str) { str = str + "5678"; console.log(str); return str;}var s = "1234";console.log('aaaa',a(s), s);// 打印的结果12345678aaaa 12345678 1234 如上代码中可以得到结果,如果是按值传递,不管方法a中的赋值结果如何,都不会改变方法外部的变量值。 哪些是按值传递的呢?原始类型(number、string、boolean、null、undefined)的这五种类型是按值传递的。原始类型在内存中是存在栈中,而对象类型是存储在堆内存中,理解对象的内存存储可以让你对传递的概念等有很好的帮助。 按引用传递看看下面这个练习题的打印结果12345678910111213141516171819var arr = [1, 2, 3, 4];function a (input) { return input.push([5, 6, 7, 8])}function b (input) { input = '2234' return [input].concat([5, 6, 7, 8])}console.log('aaa', a(arr), arr);console.log('------------');console.log('bbbb', b(arr), arr);// 打印结果// aaaa 5 [1, 2, 3, 4, [5, 6, 7, 8]]// ------------// bbbb ["2234", 5, 6, 7, 8] [1, 2, 3, 4] aaaa list是个Object, 它的值存在堆内存中,arr指向堆内存的地址,arr的值变了,arr也就跟着变了。这就是引用传递。 其中的5是list.push返回的数组长度 Array.prototype.push() bbbb 当函数内部对其重新赋值(即newValue !== oldValue),传入的外部变量不会受影响; Array.prototype.push() 克隆针对对象的引用传递,改变的是引用的值,无法创建一个一样的对象。有两个解决方法,一种是自己写的克隆的方法 ,一种Object.assign() 不过两种都有缺点,自己写clone比较麻烦,下面代码里的兼容性也不好,arguments.callee在ES 5的严格模式中是背禁用的 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748深度拷贝方法1 function clone(obj) { var o,i,j,k; if(typeof(obj)!="object" || obj===null)return obj; if(obj instanceof(Array)) { o=[]; i=0;j=obj.length; for(;i<j;i++) { if(typeof(obj[i])=="object" && obj[i]!=null) { o[i]=arguments.callee(obj[i]); } else { o[i]=obj[i]; } } } else { o={}; for(i in obj) { if(typeof(obj[i])=="object" && obj[i]!=null) { o[i]=arguments.callee(obj[i]); } else { o[i]=obj[i]; } } } return o; } 深度拷贝方法2 var deepCopy= function(source) { var result={}; for (var key in source) { result[key] = typeof source[key]===’object’? deepCoyp(source[key]): source[key]; } return result; }","tags":[{"name":"javaScript","slug":"javaScript","permalink":"http://www.lixingdecai.com/tags/javaScript/"},{"name":"对象","slug":"对象","permalink":"http://www.lixingdecai.com/tags/对象/"}]},{"title":"关于ECMAScript 5的严格模式","date":"2017-04-17T14:27:39.000Z","path":"17/04/about-use-strict/","text":"最近看一些源码的时候经常看到’use strict’ 严格模式,对这个概念有点模棱两可。感觉 ES 5的严格模式和ES6有些地方有点相似,比如变量提升。这个可能注定要被历史掩埋,翻出来整理下纯粹为了好玩。 “use strict” 是 ECMAScript 5引入的一条指令。指令不是语句(但非常接近于语句) 先科普下指令和语句之间的两个重大的区别它不包含其他语言的关键字。指令仅仅是一个包含一个特殊字符串直接量的表达式。对于没有支持ECMAScript 5解释器的浏览器,“use strict” 只是个没有副作用的表达式语句。将来如果 user被作为关键字的时候,将不需要引号 ps:大部分浏览器都支持ECMAScript 5的 javascript解释器, 但是 ie8对ECMAScript大部分功能支持,但不支持strict mode 它只能出现脚本代码的开始或者函数体的开始、任何实体语句之前。这里其实有点疑义,’use strict’可以不在第一行,只要前面不是产生实际运行结果的语句,比如直接跟在一个空的分好后面。 12345678<script> "use strict"; console.log("这是严格模式。"); </script> <script> console.log("这是正常模式。");kly, it's almost 2 years ago now. I can admit it now - I run it on my school's network that has about 50 computers. </script> 上面代码中,前一个script标签是严格模式,后一个标签不是严格模式 严格模式和非严格模式的区别严格模式下,this指向的值是undefined, 非严格模式下this 指向的是全局变量123456789101112function (){ return !this;}非严格模式下 this指向的全局变量,!this返回 falsefunction() { 'use strict' return !this;}严格模式下 this指向的是undefined, 所以!this的值是 true 可以利用这种特性来判断javascript实现是否支持严格模式1234var isStrictMode = (function() { "use strict"; return this === undefinded}()); 严格模式禁止使用 with语句with语句用于扩展临时作用域链 123456789101112with(document.form[0]){ name.value = ''; address.value = ''; email.value = '';}以上的 with语句等价于 ->var form = document.form[0];form.name.value = '';form.address.value = '';form.email.value = ''; 但是必须一提的是,with 有两个致命缺点。一个是难于优化,一个是运行比较慢,所以在严格模式中是被禁止使用的。 严格模式中,所有变量都要先申明如果给一个为申明的变量、函数、函数参数、catch从句参数或全局对象的属性赋值,将会抛出一个错误异常。这个跟ES 6中的没有变量提升一样,变量得先定义在使用。 在非严格模式中,这种隐式申明的全局变量的方法是给全局对象新添加一个新属性 call() 或 apply()在严格模式中,通过 call() 或 apply() 来调用函数时,其中的this值就是传入的第一个参数 在非严格模式中,null 和 undefined 值被全局对象和转换为对象的的非对象值所替代 只读和不可扩展对象严格模式下,给只读和不可扩展对象创建新成员都将抛出一个类型错误非严格模式,这些操作只是简单的操作失败,不会报错 eval()在严格模式中,传入eval()的代码不能再调用程序所在的上下文中声明变量或定义函数。变量和函数的定义是在eval()创建新的作用域,在eval()返回时,作用域就被弃用了。 正常模式下,eval()的作用域取决于所处全局作用域,或者处于函数的局部作用域。 1234567'use strict'var a = 1;console.log(eval("var a = 5; a")) // 5console.log(a); // 1 arguments 对象在严格模式,传入参数arguments拥有传入传入函数值的静态副本。所以你不允许对arguments进行操作。 1234567891011'use strict'function f() { arguments ++; // 报错:SyntaxError: can't assign to arguments in strict mode}try { } catch (arguments) { } // 语法错误function arguments() { } // 语法错误var f = new Function("arguments", "'use strict'; return 17;"); // 语法错误 在非严格模式,arguments的数组元素和函数参数都是指向同一个值的引用。 12345678910111213function f1(a) { a++; return [a, arguments[0]];}f1(1); //非严格模式下输出为 [2,2];function f2(a) { 'use strict' a++; return [a,arguments[0]]}f2(1) // 严格模式下输出位[2,1] delete严格模式下,就变得严格的,当 delete运算符后跟随非法的标识符。将抛出一个语法错误。 1234567'use strict'delete a; // SyntaxError: applying the 'delete' operator to an unqualified name is deprecated非严格模式下delete a; // false 同名错误在严格模式中,在一个对象直接量中定义两个或多个同名属性将会报错。 但在浏览器是了下同名并不会报错 12345678重名的属性'use strict'var a = { b: 1, b: 2}严格模式和非严格模式下同名属性都不会报错。 重名的参数1234567"use strict";function f(a, a, b) { // 语法错误 return ;} 八进制严格模式是不允许使用八进制整数直接量,以0为前缀,而不是已0x为前缀。 caller匿名函数无法在内部调用自身 12345"use strict";var f = function() { return arguments.callee; };f(); // 报错 TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them 目的 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为; 消除代码运行的一些不安全之处,保证代码运行的安全; 提高编译器效率,增加运行速度; 为未来新版本的Javascript做好铺垫。 缺点现在网站的 JS 都会进行压缩,一些文件用了严格模式,而另一些没有。这时这些本来是严格模式的文件,被 merge 后,这个串就到了文件的中间,不仅没有指示严格模式,反而在压缩后浪费了字节。 更多内容可以参考阮老师的文章 Javascript 严格模式详解","tags":[{"name":"ES 5","slug":"ES-5","permalink":"http://www.lixingdecai.com/tags/ES-5/"}]},{"title":"小米新应用-美柚App 开发笔记","date":"2017-03-21T13:22:58.000Z","path":"21/03/xiaomi-newapp/","text":"小米联系公司商务,希望能在小米的新应用上能够进行合作,然后也就有了这个项目 小米新应用-美柚采用流行的前端开发模式,贴合主流前端开发者的思维习惯,同事大幅提升应用的性能,提供大量前端环境无法使用的系统能力,以及很多第三方服务的对接能力。这个相对于阿里的YunOS cloudApp 就好太多了,cloudApp虽然技术用的也是 js,但是开发思维习惯还是用的是android的,画个页面,你先得写个布局layout.json,写个动态样式在页面的 xml文件中搞不定,还得在页面的控制器里用 js去写各种样式。这也是为什么我们觉得小米新应用可以弄,虽然后来发现他的坑也不少。 从开发体验来说,小米的开发体验相对于阿里的YunOS还是不错的。开发环境有三个部分组成platform: 一个运行在小米手机上的 apk,tools: 类似 SDK, 具有命令行打包工具,可将新应用打包成 zip包,运行在 platform 上demo: 具有一个简单的静态项目的示例 和一个组件接口调用示例。 环境搭建环境搭建上,还是相对比较简单的。花了半天的时间,就能工程跑起来了。 但是频繁的更新还是挺繁琐的,得先下载SDK然后替换掉本地的,然后再升级你工程的SDK,下载最新的apk并安装替代你的手机,在运行你的新应用工程,部署到手机的platform(apk)上。理想状态是在本地工程通过在线安装直接升级项目依赖的SDK包,当然,现在处于内测并且是开发阶段,可以理解。 开发流程先要命令行 npm run serve 起一个本地服务,手机安装platform,通过这个服务去跟新安装项目生产的zip包。最开始的命令行运行npm run dev 生成zip包,再通过手机刷新获取,操作繁琐,修改了某个代码,想要看个效果平均需要1分钟的时间(因为有时候会出现更新失败)。 现在优化后,有自动监听代码变更,platform自动拉去更新后的zip包。网络状况正常的情况,一次更新需要5s左右时间。 但是你在连续两次保存时,容易出现 存在问题 不能可视化编程,开发成本非常高,开发效率低。例如我一个子模块是否100%填充了父容器,我得给父容器和自容器各自设置一个背景色。 不能代码调试。解决办法,只能打log来定位(成千上万行log))。当出了问题时,简单的展示页面勉强还可以排查,但如果设计的负责的业务时,比如在做经期相关逻辑运算时,逻辑分支众多,打log都不定能找到错误点。 代码检测功能很弱,很多时候的报错无法定位出错点,比如:有一次页面少了一个没有关闭,在进行点击日期选择组件的时候报了个诡异的错误,这边花了三个小时时间把代码翻了一遍也没找出结果。求助洪光,才知道少了个闭合。等等 沟通成本很大,跟小米那边技术人员洪光一对一对接,每次有问题,如果能解决,如果是我这边的问题,解决起来,一来一回要好几个小时,如果是他们的问题,他们还要发包更新版本提供支持,可能要隔天解决。 技术难点,由于目前小米那边是页面和页面间隔离的,不能进去不同页面间对对象的实例化操作。为了能出个1.0版,切换页面通过存读数据库来进行操作。所以可能,是切换页面性能很弱的原因。 以上是存在的比较大的问题,小米那边也在迭代开发中,还有各种各样的小问题,他们自己也是知道的。 暂时不建议投入经期2.0,原因有二 成果的不确定性,我不能保证能不能出成品,(1.0我也是周五下午3、4点确定能出东西,太刺激了)。不能调试,大小问题(都不懂是谁的问题)都得依赖小米开发人员。因为美柚app是个工具类app, 更多的是业务逻辑,计算太复杂了,代码没法跟踪。 时间的不确定性,因为得依赖小米那边,一来一回就是好几个小时过去,或者一天过去。我也不知道什么时候能做出来 1.0 做了哪些东西 计算显示用户经期, 设置经期长度,周期长度 显示用户记录数据 用户手机号快速登入,发短信,设置密码操作, 贴士列表、贴士详情,关于美柚等页面展示 1.0的坑顺便说下1.0留的坑吧,时间比较赶,为了能出版本,我就自己决定了一些东西。 改变经期状态,更新的内容不会刷新到页面上,首页初始化默认了四条贴士,所以看起来跟写死的一样。 没有上传、下载服务端用户经期数据,周五早上才给接口,所以我也不确定有没有合并。 没有遮罩、没有加载动画等等细节都没有。 因为没有缓存,也不知道全局变量,每次操作都是通过存读数据库来交互的,所以代码逻辑改的很乱。 成果展示从上手到开发,两个星期的时间赶出的成果;成果如下图: Your browser does not support the video tag.","tags":[{"name":"笔记","slug":"笔记","permalink":"http://www.lixingdecai.com/tags/笔记/"},{"name":"混合应用","slug":"混合应用","permalink":"http://www.lixingdecai.com/tags/混合应用/"}]},{"title":"SEO学习分享和培训文档 (附思维导图源文件)","date":"2017-02-27T13:22:05.000Z","path":"27/02/SEO_DEEP_LEARNING/","text":"宝宝树 vs 美柚 SEO概况 2017-02-16 指标类型 宝宝树 美柚 中文网站排名 187 16161 母婴网站排名 3 日均IP 196万 30 日均PV 1000万 30 百度权重 8 4 360权重 6 2 响应时间 203毫秒 49毫秒 预计百度流量 44万5587 2704 百度移动流量 16148(-1073) 14211(+2320) 百度收录数 1亿3700万 1万1 反链数 4577 73 搜索引擎与SEO SEO 思维导图(xmid)下载地址 SEO 思维导图(原图)下载地址 什么是SEO SEO: 搜索引擎优化(Search Engine Optimization);指为了提升网页在搜索引擎自然搜索结果中的收录数量及排序位置而做的优化行为。 对于网站和用户,搜索引擎优化是一种免费的引流渠道。对于搜索引擎,SEO是一种网站建设和优化需要遵循的规则。 SEO 是职业 还是 技能? 在不少公司中,都有专门的SEO部门–>搜索引擎中拉免费的流量、提高搜索流量转化率的相关用户体验、运营的一职多能的角色。 SEO 不是机械的发链接和堆关键词。 不同层次不同理解 SEO是技术 关键字,描述,各种链接等 觉得SEO各方面都是通过技术实现的 SEO是策略 制定一系列SEO相关的策略计划,指导技术,编辑,数据分析及外链专员等人员进行专项工作。 SEO是艺术 挑逗搜索引擎或更深入研究搜索引擎 技术不能支撑起SEO的全部,但技术是SEO的重要组成部分。会技术的不一定是SEO大牛,但SEO大牛肯定技术也很牛。 ps:前端做SEO有天然的优势,有兴趣去研究,美柚如果能给这个机会的话,会是一个很不错的发展方向。 天下无难事,只要肯放弃 为什么要SEO引流。 为了从搜索引擎中获得更多的免费流量,以及更好地展现网站形象。 SEO五个阶段 收录 排名 流量 转换 重复上述 搜索引擎工作原理 搜索引擎主动抓取网页的步骤 派出Spider : 按照一定策略把网页抓回到搜索引擎服务器 内容处理 : 对抓取回来的网页进行链接抽离、内容处理,消除噪声、提取该页主题文本内容。 中文分词 : 对网页的内容进行中文分词、去除停止词。 索引 : 去重,对剩余网页进行倒序索引,等待用户的检索 搜索引擎工作流程 查询分析:查询关键词分词 缓存机制:查询缓存中是否有该关键词的查询结果 网页排序:没有缓存,索引库的网页进行调取排名 反作弊: (最重要 也是作弊最多的部分) 内容相关性,重要性(链接权重分析),用户体验高低(搜索结果页的使用体验)。 Spider 分类按网络上所有spider 的作用及表现出来的特征进行分类:批量型、增量型、垂直型 批量型针对性;有明确抓取范围和目标,设置抓取的时间,数据的限制、固定范围内页面的限制。 增量型通用爬虫 。追求广而全的抓取,没有固定目标,范围和时间限制。尽可能全的抓取网页,还要针对已更新的网页进行相应的再次抓取和更新 垂直型聚焦爬虫。具有特定主体,特定内容或特定行业的网页进行抓取。 Spider 抓取策略spider 抓取的页面类型可分为:已抓取页面,待抓取页面,可抓取页面,暗网中的页面。 针对这些页面的爬虫抓取策略:深度优先策略、广度优先策略、重要页面优先策略、大站优先策略 深度优先策略一条连接爬到底,再返回上一层 广度优先策略一层页面爬完,再爬更深一层 1其中:深度优先策略和广度优先策略是抓取全网的策略。但是爬虫的资源的有限性,决定了爬虫资源有限针对重要优先抓取。 重要页面优先策略重要性的定义:受寄主站点本身质量和权重,导入连接的多少和导入连接的质量 大站优先策略大站的定义:稳定的服务器、良好的网站结构、优秀的用户体验、及时的咨询内容、丰富的内容类型、权威的相关资料,庞大的网页数量,大量高质量的外链 分布式Spiderspider数量众多,涉及分布式计算,确保spider作业不重复 暗网抓取暗网:是通过普通抓取策略 永远抓取不到的网页。 解决办法: 站长提交资源。 百度数据开放平台提交结构化数据。 降权蜘蛛该网站被降权或者屏蔽,百度会把该站点的抓取任务分发给这个spider。如果有这个ip的spider 来访问你的网站,恭喜你,你的网站出问题了被降权或者屏蔽了。 spider和普通用户的区别 spider 可以分辨隐藏内容,黑链等 spider 没有Referer,普通用户有 spider 不支持cookie spider 不会主动注册网站 spider 对于动态参数网站,可能会死循环 spider 不能分辨是原创 用户体验普通网页的用户体验: 123451. 感官体验:试听上的体验,舒适性2. 交互体验:操作上的体验,易用、可用性3. 情感体验:心理上的体验,友好性4. 浏览体验:浏览上的体验,吸引性5. 信任体验:信任体验,可靠性 SEO 判断体验 12341、简介的页面,广告不会干扰内容页面,没有大量弹窗跳转(感官体验)2、网站品牌、网站曝光度、网站备案(信任体验)3、网页在搜索结果中的点击率,又反悔搜索引擎二次搜索的比略,内容原创性、时效性、丰富性及更新频率,网页标题和内容相关性(浏览体验)4、网页功能性,评论数量,踩顶次数、页面分享次数、页面风向次数等用户投票数据(浏览体验) 关键词研究 关键词研究的意义: 精准的关键词 容易在搜索引擎中获得排名 从SEO的角度根据所挖掘的关键词 来为网站提供运营方向 关键词分类按搜索目(这里所列的)导航类不记得网址 或者 懒得输入网址 使用的关键词 精确型 QQ空间登入 等 12钓鱼网站使用没有具体的研究价值 模糊型 1不知道是找官网或者找官网相关新闻或者评价之类的信息 事务类重点关键词,通过这些关键词来访的用户有比较高的转化率 具有明显动作目的而搜索的关键词: 比如购买意向,比如大姨妈计算,大姨妈来了相关贴士 信息类寻找某种信息使用的关键词。数量占总搜索词的绝大多数,也是绝大部分网站抢占流量空间最大的一类关键词 典型的例子:京东把每个评论做成一个页面。标题设计:“商品名 ‘评论标题’ -京东品牌名” 百度搜: 美观大方 安装方便 按关键词长短长尾关键词、短尾关键词 在考虑关键词长短的时候,要注意两个理论 2/8理论80%的经历和资源来主攻20%的核心关键词的优化,这部分关键词如果能优化成功,将会带来很可观的流量。彰显网站在行业中的地位。 长尾理论大部分的长尾关键词的搜索量虽然很小,但是核心关键词的数量有限,一定的长尾的累积搜索量肯定比核心多 按关键词热度 热门关键词;流量非常大,但词量少;”魔兽世界” “dota” 一般关键词; 一定搜索量,介于长尾和短尾之间。 “iphone 7 长度” 冷门关键词;偶尔有那么几次搜索量的关键词,搜索量极低。“碰到女生不会说话怎么办” 关键词挖掘 同行竞争对手 针对资源批量扩展 按属性扩展 搜索引起提供的数据 小工具: 很多站长工具都提供 关键词挖掘工具 关键词处理选择挖掘出来的关键词进行筛选,布局到网站中 与内容相关 搜索量大 竞争小 分组 适合首页和核心目录 适合扩展子目录 适合专题页面 适合布局到内容中去 适合资源聚合页面 细分:搜索量 竞争强度 词性 商业价值及所属细分类等因素 关键词间建立相关关系分布到网站中。架构比较大,内容比较多的网站是有必要的。 关键词部署原则 每个页面只部署2~3个关键词 除内容页外的页面,页面之间的关键词不可重复,甚至不可太相近 对于太相近的关键词或同义词进行组合部署,尽可能分配到一个页面中,如果站内资源丰富,可以进行单独部署 除内容页外的页面,部署的关键词最好是规范的关键词,没有太多定于形容词 方法参照关键词分组。出去网站首页和主要栏目页优化一些高搜量,高竞争强度,高行业地位的关键词之外,其他关键词根据关键词本身的搜索量、长短性质、规范层度就可以布局到内容页、专题页和聚合页中去了。 网站分析 网站数据分析基础数据这是长期工作的内容 数据可视化处理:数据转为图形 比如针对收录,要通过对短期数据的分析来进行中长期的演化,从而获得优化收录需要注意的问题。另外还包括了重点栏目的长期跟踪、外链数量的跟踪等等。 关键词分析需要持续对网站 关键词数量 和 排名 以及转化率等数据进行持续跟踪,并且作好记录,并通过SPSS统计学软件进行统计分析,查看是否具有统计学意义,当然目前也有很多专业的网站能提供相应的软件工具来帮助进行统计学分析,从而掌握关键词数量和转化率等趋势和发展,从而有效提升数据分析能力,为网站的SEO优化提供参考。 流量分析竞争对手分析搞SEO优化,最终目的是超过竞争对手,成为行业领军。知己知彼才能百战百胜。 网站收录数据 外链来源 数量数据 关键词种类 相关关键词排名 网站结构和内链布局 分析页面和内容 站内优化 基础优化 404页面:减少网站跳出率,提升用户体验。(tips:腾讯的404计划) robot.txt (跟spider交互的唯一文件) 完整整体结构优化 (树形结构,层结最好不超过三层,超过三层可能就爬不了了。不要采用主流搜索引擎难于识别的形式,内容尽可能用文字形式表现,如果非要使用到图片或者Flash也要加个标签,说明文字。虽然现在开始有针对图片的搜索引擎) 锚文本布局:规划布局好站内的锚文本绝对是一件富有价值的工作,而站内的锚文本遵循的原则跟外部链接没有多大区别。 META标签优化:title、keyword、decription 清理死链 网站地图 :它就是一个页面,上面放置了网站上所有页面的链接。当用户在网站上找不到自己所需要的信息时,可能会将网站地图作为一种补救措施。另外,搜索引擎蜘蛛非常喜欢网站地图,有利于蜘蛛的爬行抓取。 内部权重分配 123456789101112131415161718 一等页面 关键词搜索量很大,比如首页,栏目页,专题页等,一旦排名会获取很大流量,那最好整个网站每个页面都有指向一等页面的链接,并且站外也要做外链。 二等页面 关键词搜索量一般,比如文章页等,但也能带来流量,那针对这些页面链接最好长期在一等页面中存在,另外,再发布文章的时候,多给这类页面做内部链接,如果有精力也可以对这类页面做点外链。 三等页面 几乎没有搜索量,比如很多企业站的新闻等,但这类页面的存在可以提高整个网站的收录量以及给以上两种页面提供权重。 营销页面 本身没有搜索量,页面流量来自上面三种页面,靠站内引流,这类页面只要是那些产品介绍页,引导消费页等。 一个营销类网站最好做到上面几个页面的划分,同时我们也可以这么归类,见图 转化层:就是上面说的营销页面,网站将大量流量引流到这里进行消化,让流量变成现金。 营养层:就是上面说的三等页面,给别的页面提供权重,本身不需要排名。 流量层:就是上面说的一等页面和二等页面,通过站内和站外的权重集中获取很好的排名,又将流量引流到转化层。![](http://upload.admin5.com/2014/0211/1392089748190.PNG)摘自:http://www.admin5.com/article/20140211/536384.shtml 硬件优化 代码优化 恰当的使用标题标签 避免重复页面:每个页面包括标题、描述和关键字等都应该不一样,需要注意的是很多设计师会做一个通用的模板,而用的时候又忘记修改。标题一定要是具有独特性的! 网站导航优化:网站的导航全站通用,至关重要,尽量用文字导航,不要用图片和flash等,若一定要用图片请一定加上alt属性。Flash则尽量避免,Flash的效果是很好的,但加载很慢,搜索引擎也无法读取Flash文件。 精简代码:符合web2.0标准,使用div+css设计网页,合理布局标签尽量减少div层,使用描述标签,精练描述你的网页网络销售培训,将网站重点内容与经常更新的内容代码尽量靠近的位置。页面不要超过125K 图片与文字链接优化:给所有图片加上alt描述属性。 js、css脚本优化: 网站的JavaScript和CSS等文件一律外部调用,不要把代码写在网页中,并且尽量减少脚本文件个数,这样不仅仅有利于网页加载速度也有利于搜索引擎蜘蛛的抓取! 网页布局优化: 面包屑型导航,树状扁平化结构。首页点击不出三次可以到达网站任何一个页面,任何页面都可以很快的回到想要的页面。文章内容部分先于其他部分显示,设置上一篇、下一篇文章,根据文章的关键词设置“相关文章”,如果文章内容多分几页显示,需要保持每页的网页标题、文章内容均不同,避免出现复制内容问题 。 网站优化 不要和域名重复: 对于国内区别不大。因为他们一般对于URL的关注没有国外那么敏感,不过建议最好还是使用清晰独立的URL,尽量避免和域名重复。 URL最好静态化: 静态化有利于搜索引擎抓取,另外对于一些必要的转向尽量使用301处理,同时建立一个404导航页面以免出现打开错误时可以帮助导航。 管理文件扩展 URL被惩罚: 如果你怀疑这个URL有被搜索引擎认为作弊的嫌疑,可以检查URL里:可疑的关键词、符号、二级域名深、域名深度、数字。 管理好文件扩展: 不要用.exe之类搜索引擎无法识别的文件类型来结尾,这种会导致搜索引擎无法收录。 URL的长度: 在URL里最好不要超过3-5个关键词,Google Matt Cutts 说如果超过5个关键词,该url的权重就会被相应的降低。当然这个是相对的,并不是超过5个关键词的URL就不会取得好的排名,毕竟URL只是其中的一个部分而已,而对于一个优秀的SEO人员可能是寸步必争,不会轻易放弃每一个可能超越对手的地方。并且最近的研究显示,在排名较好的位置里面,较短的URL获得的点击率是长的2倍,所以为了你的排名和点击率,最好还是用较短的URL。 做好网站首选域: 首选域能很好地把权重集结到某个域名上,试想,一个首页,有动静态,www,不带www的域名等四条路径,这对SEO的工作及搜索引擎的抓取压力是很大的,把首选域名做好,规划好首页路径,默认首选路径为www.365soudao.com/index.html。这样对以后的工作是非常有效的,特别是新的网站,一定要做首选域。 文件优化 Robots.txt为什么设置Robots.txt在进行SEO操作的时候,我们需要告诉搜索引擎哪些页面重要哪些页面不重要,重要的页面让蜘蛛进行抓取,不重要的页面进行屏蔽可以减少网站服务器的负担。 在robots.txt文件中设置网站地图迷路时的指路牌 路径问题 绝对路径/相对路径:在蜘蛛协议中,Allow和Disallow后面可以跟两种路径形式,即绝对链接、相对链接。绝对链接就是完整的URL形式,而相对链接只针对根目录。这是重点记住。 斜杠问题:Disallow: /seojc表示禁止抓取seoic这个目录下的所有文件,如:seojc.1.html、seojc/rmjc.php都不允许抓取; Disallow: /seojc/ 表示禁止抓取seojc这个目录下的文件,即允许抓取seojc.1.html,但是不允许抓取seojc/rmjc.php。 内容优化 坚持更新文章,丰富网站内容,抢占更多关键词 建设企业新闻栏目,导入首页权重:不能独立建设资讯栏目的企业站,建议可将更新的重点放在企业新闻这一块。相比上策,中策的更新量要少得多,站点收录量少的多,关键词排名的效果相应也要差上一大截。 有SEO意识的内容团队:能够围绕关键词,长期稳定的为网站推广企业站提供高质量、原创的内容; 强有力的技术支持:能够按照优化团队的要求,适时的为企业站建设新的内容平台。 新闻内容有意识的围绕关键词来组织:这需要撰写新闻内容的网络营销企业人员先接受SEO内容建设的培训,在写作时有意识的考虑到关键词布局。 站外优化 业内有句话:内容为王,外链为皇。直接反应了外链建设在SEO中的重要性。 外链的作用 得到链接最多 质量最好的网页 高质量 高权重的网站指向的网页 锚文本也是被链接网页的主要内容 获取外链的方法及注意事项友联交换和注意事项寻找交换对象的方法 QQ群 站长和SEO论坛 链接交换平台 自己网站上挂起交换链接联系方式 自己找 判断是否适合交换 PR值 内容 收入量 备案 site对方域名查排行 百度权重 导出链接多少 PR输出值 警惕的小把戏 加上链接后而已删除 源码中看不到友情链接 禁止友情链接导出权重 垃圾站或链接农场做交换链接 不推荐接受友情链接专业 正文中交换链接 严格控制数量和相关性 锚文本多样化 普通群发有害无益链接买卖链接诱饵(最后的方法)1234发布原创文章: 等到自己网站收录以后,再转载:等到自己网站收录以后,再转载提供优质资源(视频)在站内制造话题分享插件使用 付费新闻源软文工具 Chinaz 站长之家1234567891011121314151617181920212223242526272829303132333435363738394041域名/IP 域名到期查询 过期域名查询 WHOIS 查询 IP 查询 同IP 网站查询 DNS 查询网站信息查询 Alexa 排名 网页备案查询 网页检测 HTTP状态查询 查看网页源代码 机器人模拟抓取 robots.txt 生成 移动适配生成 网站速度测试 ping 测试 Wap 适配 网站 GZIP 压缩SEO 查询 SEO 综合查询 移动SEO 查询 友链检测 反链查询 收录查询 META 信息挖掘 PR 查询 关键词排名查询 关键词挖掘 关键词优化分析 竞争网站分析 SEO 优化建议百度权重查询 百度权重 百度移动权重 360权重 360移动权重 神马权重 指数批量查询 关键词指数排行 团队协作 没有恒定的排名规则,造就了工作效果的不确定性,带来目标设定和绩效考核的一定难度 团队组成 leader 数据分析专员 页面优化人员 安全技术人员:保证服务器和网站安全 根据SEO需求配置好服务器 根据SEO方案对网站程序改动 内容编辑 外链专员:培养团队外链资源,发掘有效的外链平台和方法,平衡外链中使用的锚文本。 KPI & KCIKPI: 关键绩效指标 KCI:关键胜任能力指标,把员工中的能力,个性,冬季,态度等进行量化和定性。 如果只使用kpi,为达目的不折手段,使用群发软件或者垃圾链接生成软件来完成外链数量 工具针对于团队的自动化管理。把工作、数据和人员进行一一对应,统一调配、监控和管理的工具 博求SEO团队管理系统 蓝狐SEO团队管理系统 外包适当外包 其他名词解释 SEM:搜索引擎营销的基本思想是让用户发现信息,并通过(搜索引擎)搜索点击进入网站/网页进一步了解他所需要的信息。 SEM的方法包括搜索引擎优化(SEO)、付费排名、精准广告以及付费收录 PR:PageRank 是迷恋 Google 的人们用来测试其站点在 Google 中的排名的一种度量标准。SEO 和搜索引擎营销(SEM)专家也使用这个术语描述网页在 SERP 中的排名以及 Google 根据排名算法给予站点的分数。无论如何定义,PageRank 都是 SEO 的重要部分。 黑帽:作弊。索引擎禁止的方式优化网站。 比如,群发留言增加外连,这是一个典型的黑帽行为。因为通过这个方式增加外部链接影响了其他站点的利益,同时影响搜索引擎对网站排名的合理和公正性。搜索引擎要制止这个做法,所以这个做法就被称为黑帽 白帽:采用SEO 的思维,合理优化网站,提高用户体验,合理与其他网站互联。从而使站点在搜索引擎排名提升。 关键词堆积:是一种作弊技术,通过它关键词被过度使用,仅仅为了吸引搜索引擎。 内容农场:为搜索引擎制作大量低质量内容的网站 链接农场:在 SEO 术语中,链接场是指一个充满链接的页面,这些链接其实没有实际作用,它们只作为链接存在,而没有任何实际的上下文。那些采用运用黑帽SEO 方法的人利用链接场,在一个页面中增加大量链接,希望能通过这种方式使 Google 误认为这个页面很有链接的价值。 链接工厂:是一种作弊技术,通过它搜索营销人员建立几十个或者上百个能被搜索引擎爬 谷歌跳舞:谷歌跳舞这个名词通常用于描述谷歌搜索引擎对搜索结果进行更新、重组的过程。谷歌一般每个月对其搜索数据库进行一次更新。新的网页被加入,无效网页被删除,对收录网站进行全面深度检索,也可能在这期间调整算法。在“跳舞时期”(三到五天内),谷歌的搜索结果会有大幅度的波动,几乎每一分钟都会有变化。这一更新过程可以很容易地通过搜索结果的显著变化来识别。“跳舞”一般持续几天时间,跳舞结束后,Google搜索结果和网站外部链接数量趋于稳定,直至下一个周期的到来。 家族内链接:在两个有相似IP地址、或者相似数据库信息,或者定向锚文本间网站的链接可能被搜索引擎认为有偏向是在彼此中立方之间的。 - 内链:也叫站内链接,网站内部页面与页面之间的调整的链接交内链。一个页面要被收录,首先搜索引擎蜘蛛要能爬到你的链接,在爬行的过程中蜘蛛会顺着一条链接,爬到另一条链接,所以内页就需要良好的部署,不定期检查站内是否存在死链或断链。如果想要有一个好的排名就需要适当添加反链来引导搜索引起。像导航,Tags等等都属于内部链接。 外链:SEO外链就是所有指向自己网站的链接,它存在的目的是告诉搜索引擎这是条路,这条路可以走到我的网站,指导并且吸引蜘蛛的爬行抓取路径,也就是大家所熟知的路标和引导的作用,仅此而已,记住只有一个指引的作用。 反链:准确的来讲应该叫做反向链接。反向链接指的是两个网页之间直接的关系。比如:有两个站,A和B,A站好比是自己的网站,B站是可以添加链接的网站,这样你把A的域名填写到 B的站内 这样对于你来说就曾加了一个反向链接。 反链也属于外链的一种。 百度快照:每个被收录的网页,在百度上都存有一个纯文本的备份,称为“百度快照”。百度快照功能在百度的服务器上保存了几乎所有网站的大部分页面,使您在不能链接所需网站时,通过百度快照也能正常浏览网页。 短尾关键词:字数比较少的关键词,比如育儿、美容、经期。一般竞争度会很大 长尾关键词:字数比较多、比较具体、搜索量比较低的关键词。例如:宝宝辅食制作100款,厦门理工招生简介 日均IP:指独立IP数。00:00-24:00内相同IP地址之被计算一次 日均PV:Page View, 即页面浏览量或点击量,用户每次刷新即被计算一次 日均UV:即Unique Visitor,访问您网站的一台电脑客户端为一个访客。00:00-24:00内相同的客户端只被计算一次。 百度权重:各个网站根据目标网站的各项数据和自己设置的公司计算出来的 提高权重的思路:1、外链:建设高质量 高数量的链接(很大层面) 2、网站内容建设 3、增加网站收录量 4、增加网站品牌知名度 5、提高网站在社交网站的中的传播度 百度快照:自动生成的临时缓存页面。临时缓存网页的文本内容。 沙盒:搜索引擎对新站的考核期。慢慢淡化 常用命令 SITE:收录量 例如site:www.meiyou.com domain: domain只能查到Title、description 页面内容和URL中包含所查询字符串的网页。 inurl/alinurl:和site指令一样,但比site不靠谱。 title/intitle/allintile:限定在网页标题 filetype:文件类型;filetype:pdf 菊花台 inanchor:搜索锚文本 ETag在我们的sitemap配置了ETag之后,对日志一段时间的监测发现,其sitemap响应时间以及耗时的平均时间均大幅度下降,爬虫访问sitemap文件的次数有所增加,对于收录而言,通过图表也能看出相对的增长曲线,我们的整体收录率大致提升范围在2% – 5%左右。所以在此,强烈建议大家设置sitemap的ETag,简简单单的一个小动作就能看到相对明显的效果还是很不错的。 SPA的SEOspa做seo其实是分情况的,比如微博根本就不考虑seo,比如用有,tb,天猫也不考虑,因为他们都是封闭的,自主体系的不考虑长尾的应用。那么比如像博客产品,简书啊,这一类的spa应用肯定就要考虑seo给自己引流了。一般分几种情况来解决。 针对浏览器搜索引擎蜘蛛,对应生成一套专门给蜘蛛看的页面,nginx ua检测即可,转发到对应的蜘蛛引擎程序上。 使用前后端同构的方法进行页面渲染,比如react是支持php渲染的,完全可以做到蜘蛛来了就服务端输出,正常用户来了,则采用混合输出,比如首屏使用后端同构,后续功能使用前端渲染。 使用phantomjs对spa页面做抓取,再转发蜘蛛的ua请求提交回给蜘蛛。 后端对每个前端的controller同步做一个后端的实现,前端的controller使用history replaceState 弃用!#这种路由。当然之前这种方法用的少,主要是因为replaceState方法的兼容性问题,目前看来这种问题可以忽略了。因为很多网站不支持ie8了!","tags":[{"name":"SEO","slug":"SEO","permalink":"http://www.lixingdecai.com/tags/SEO/"}]},{"title":"2016年年终总结","date":"2016-12-20T14:34:38.000Z","path":"20/12/year-end-summary-for-2016/","text":"2016年 年终总结工作:入职6个月、178天、加班总时长205小时、满勤3次(准满勤5次),迟到一次、请假半天。参与项目总数5个,完成4个,成功上线2个,全栈项目1个,开发中1个,终止1个(无产出)。所有项目都是负责核心功能、技术难度最高部分或者独立完成整个项目。 充电:业余时间看书两本,编写发布一个个人网站(技术博客:http://lixingdecai.com ),发表3.5篇技术博客。github上发表两个开源项目。 闲暇:喜欢青山绿水走到户外。湖南5日游,武功山徒步3日行,嵛山岛2日游,“穿越厦门”徒步活动。每周两小时羽毛球。平均每周看一场电影。一个月至少和朋友聚一次。 缺点:性子急,急于表现自己做事效率高,唐突冒进,适得其反,给人不稳重的感,演说能力基本为0。 优点:逻辑性强,负责,主动性强,高效,学习能力强。 感情:…… 叨叨叨叨叨的详情节点公司 2016.05.09–2016.07.03由于节点独特的“公司文化”,也可能是在高伟达安逸久了,出来很不适应吧,那个月感觉超级累,很闭塞很压抑。不到一个月就提出了辞职。 人生中第一次跳槽,不知道是紧张还是激动,反正我这尿性,就是用失眠好几个晚上来形容,到了陌生的环境,接触一群陌生的同事,感觉接触的是一群陌生的物种。 那时候很不适应,诸事不顺,没人鸟我,我也不想鸟谁,很久才开始融入进去,工作也像个劳役,那个月虽然不用加班,但是感觉很黑暗,现在回想起来还是一种很累的感觉。 不过还算幸运的是,我的上司是凯哥,对我还是很认可,考评还给了个第一。HR郑红说看我每天那么没精打采的样子,会不会怪她把我坑了,哈哈哈,跟她关系不能再好了。 最后做了一件不知道明智还是愚蠢的事情。想着既然人家花钱和诚意把你请来了,不能什么贡献也没有,于是乎花了点时间,把节点的一些不合理的现状和相对应解决办法总结发了一份邮件。但,很可惜,还是缺乏勇气和boss面对面交流。邮件止步于boss之前。邮件详情 终于鼓起勇气 从工作了四年的安逸和适应的环境中走了出来。4月份从高伟达离职,出来看看外面的世界。先到了节点科技,不到一个月就跑了;现在到了美柚,研究女生的大姨妈。 美柚 2017.07.06至今12345672016-07-06 入职7月份 加班20小时 下班打卡异常3次8月份 加班37小时 满勤9月份 加班46小时 迟到一次10月份 加班8小时 满勤11月份 加班 45小时 满勤12月份 加班 52小时 下班打卡异常2次 像所有优秀互联网公司一样好 一样开放 一样人性化。美女真的很多。入职到现在基本是持续加班的状态,不是很累,而且还感觉很充实,每天都状态满满动力十足,下班或加班回去都会自己倒腾点东西或者看看书,基本不玩游戏了。这可能就是好的工作环境的影响吧。小部门里松哥、百万、金成、为钦、丫鬟都是很不错的学习对象。而且周围隐藏了很多很厉害的人,可惜很多都不熟。公司有什么分享会,都会很愿意花时间去旁听,比如益聪欧巴的分享会、那个图像算法组,变脸的相关算法就很长姿势。 唯一的缺憾,是努力工作没有得我预期的回报,蛋疼的KPI让我很烦躁。 项目美柚推广平台 最吐槽的项目 描述: 美柚广告后台管理项目 美柚的两个盈利的方面,一个是电商平台,另一个就是广告。这个项目就是广告的管理平台1.0版本。是我进美柚的第一个项目。先说心情吧,战战兢兢 毕竟刚来公司不知道水的深浅,感觉都是大神,也跃跃欲试,急于证明下自己的能力和价值。在这个项目中,负责这个流程核心部分,新建广告的一整个流程:1、新建广告;2新建广告素材组;3新建广告素材;4、物料审核。然后就开始加班之旅。然而并没有想象中的那样,因为使用的是一个同事之前公司研发的框架。 不成熟:没有任何文档和demo,所有东西得使用,都没地方可查,一有不懂都得问他,开发完全受限与他。没有路由,无限制的完页面添加拼接html,导致最多各种页面之间的代码冲突覆盖。 不实际:概念非常大,前端面向对象编程,但却干着拼html字符串的事情。组件化思想,十几个页面根本没有可复用的必要,事背功半,结果天天加班还严重delay。 所有开发中和前端的负责人也就是这个框架的引入者争执了n次。这个项目属于跨部门,我只是被借调,没有决定权,很无奈。天天加班,最后还delay,最后绩效考核还要被扣分(还好那个月还没参与绩效),上头不知道你做了什么,背锅的肯定有你。 收获: 这是一个用后端面向对象思想开放的框架,用到很多js,暴露了我的前端js的基础是非常薄弱。事件绑定和dom事件冒泡,js闭包等等。反思是不是在盲目追求新技术的,变成了为了技术而技术。 更好: 如果有再一次来的机会,肯定不会因为时间原因而接受使用这个所谓框架,有更多的自信心去承担项目的责任。 地址:美柚推广平台,(支援做完1.0版本就撤了,今天打开看了下,体验还是差的不行) 两张截图: 在线文档项目(接口管理) 自娱自乐的项目 描述: 益聪欧巴找到我,说很急,要搞个接口管理的项目。然后那之后就在没有人跟进,自己一个人玩的很high的一个项目。 自己给自己提需求,自己画模型,自己架构设计,自己前端后端的开发,反正就是自己一人在角落干的热火朝天。这个项目的职能是:通过GUI工具帮助WEB工程师更高效的管理接口文档。在匹配美柚的自身产品特点,比如http请求里面content-type有form-data 和 raw等情况。报文头具有自定义消息的部分。 这个项目还是比较有意思的,前后端一起的全栈项目的。前端用的ng的mvc架构,gulp + webpack的自动化和打包,后端使用nodejs + express。使用mongoodb做数据存储,用redis做session的内存缓存。这个项目是仿照阿里 RAP,只是使用的技术架构不同。 收获: 从全局角度去看各开发部门的协同工作,并解决一些存在的痛点,致力于提高的开发工作效率。技术上解除并使用了一些当下比较主流的技术,mongoodb redis webpack这些技术等。 更好: 在开发完大部分功能后,由于其他工作安排,移交给为钦去跟进。如果有机会,我会持续去后期跟进,跟移动端、服务端、测试部门和产品需求好好沟通,去把这个项目优化好,做的更人性化。也把这个项目持续推进。如果还有更多的时间,我会把mock部分完善起来。自动生成Mock数据、校验真实接口的正确性,使接口文档成为开发流程中的强依赖。 做了一个月,功能完成就没有再跟进,长得有点丑。 YunOS CloudApp 无奈的项目 描述: 这是唯一没有出东西的项目。那就先简单说下都做了什么吧。 提出bug48条、抛出问题28个、给出建议7条(共7个word文档)。安装搭建的IDE版本不下8个。基本等于给阿里做测试了。 属于公司一个战略类型的项目,和阿里巴巴的YunOS团队合作,希望将来YunOS CloudApp 发布的时候能带上美柚一起。但是这个项目非常不成熟,阻碍重重,阿里的团队还在开发中,api不全,文档不全。又涉及阿里ide、device、sdk等各团队的沟通。虽然语言用的是js,但是生命周期和页面,都是使用的是android的相关技术栈。所以画一个页面真的痛苦无比。时间也是比较紧迫,十一月末出个版本。 十月底接手项目,十一月中旬结束,其中还有一个星期被抽调支援小程序。5周的工作时间。其中三周都在和阿里开发团队调试IDE和device,从最初的windows换到后来自己的mac。其中真正开发的时间才两周,只做出了一个很简陋微信美柚小程序的主页。如果再多给一个月或者几周,还是有信心做出一版美柚app。 运行也只能在ipad的模拟,写个页面得改三个文件:界面结构xml、界面布局josn、页面控制器js。 收获: 沟通能力,还有自我学习能力。跟阿里的SDK、DEVICE、IDE三个团队沟通交流。认识了很多阿里的朋友,了解阿里的工作和合作模式。 更好: 这个坑是很多人不愿做或者不会做,才丢到我这的。以后不能太注重技术上的东西,还得关注绩效,毕竟这个跟工资挂钩。或者在做之前先和领导沟通好。不然到最后会很失落,就真的是背坑了。 丑到没朋友,阿里只提供基于ipad的模拟器: 微信小程序-美柚经期 成就感项目 描述: 两周时间(一周开发一周测试),将美柚的经期日历逻辑理清楚,并搬到小程序上。因为没有任何的逻辑或者文档积累,ios 和 android两边的客户端都是各自的逻辑。时间紧迫,上班下班睡觉都是女人的大姨妈的计算。逻辑超乎寻常的复杂,点击某天需要实时计算当天是安全期、排卵期、月经期等状态,改变经期结束或者开始日,得把经期日历重新计算渲染的交互逻辑。一周开发时间基本是不可能完成的任务,所以我的成就感是也是满满的。并总结归纳出三张逻辑图,弥补公司在这个方面文档的空缺。提高了测试,产品,和开发的沟通和工作效率。 小程序本身技术上难度并不大,只要熟悉下文档和生命周期基本上没有什么大问题,我本身也是正在做YunOS项目然后被抽调过来,边开发边学习。难度本身还是来自美柚的经期日历的算法,而我对经期算法以前基本不懂,而且也没使用过美柚APP。 坑是肯定有的,毕竟它是个新的东西。但是你要是跟我一样经历过YunOS CloudApp的研发,你就不会抱怨了。至少我很满足。 收获: 1.9日成功上线。是我工作5年来第一个自己做的,可以让周围朋友使用的项目,且在经期的日记计算无卡顿和无明显bug。无比开心,感动的要哭。完成了一个基本不可能完成的任务。 更好: 时间少的可怜。还有很多代码可以优化和重构,如果有时间的话。文档缺失真的给我造成很大的麻烦,产品和我都低估了孕期的影响,和逻辑复杂度。所以后面测试的一周基本是在和测试死掐孕期这块,疲于奔命。 部分页面展示 总结的部分算法逻辑图 学习十一月份的时候,去买了个域名,然后折腾了一个博客。感觉这么折腾也是挺有意义的,可以学到很多乱七八糟的东西。其实还是培养总结的习惯,和巩固所学的内容,李姓的菜の博客。开始尝试写技术博文,但比想象中还困难,基本一篇看似很简单的都得查找很多相关资料,并实践写,配以文字总结还有心得体会。 开始慢慢接触github和开源思想,已经在准备我的第三个开源项目了,虽然都没有获得什么star。 生活天天加班,三餐吃完基本都是坐在工位上,肚子多了好大一圈肉。工作压力会很大。如果周末不下班都会想去爬爬山之类的。周末都会抽出时间去打打羽毛球,出一身汗。不然这么工作,身体很快就得废了。压力很大,爬山,看电影,听歌唱歌是我减压的方法。一个月平均两次跟朋友聚聚,喝喝酒吹吹牛,不然我怕自己会变得更不会跟人交流。 开心工作 认真生活","tags":[{"name":"年终总结","slug":"年终总结","permalink":"http://www.lixingdecai.com/tags/年终总结/"}]},{"title":"可以当做面试题的知识点","date":"2016-12-16T10:01:28.000Z","path":"16/12/my-interview-question/","text":"一些我在学习过程中觉的不错的地方,可以用来当做面试的考点或者自我提高的知识点。 js写个阶乘函数,如:5的阶乘1234567891011121314151617181920212223242526答案:1、尾调用(一般解决方法):function factorial(n) { if(n === 1) return 1; return n * factorial(n-1µ);}尾调用会形成一堆‘调用帧’的‘调用栈’,递归非常耗费内存,容易出现栈溢出(stack overflow)2、尾递归(优化解决方法)function factorial(n,total = 1) { if(n === 1){ return total } return factorial(n-1,n * total);}factorial(5);ps:尾递归的好处:避免出现栈溢出错误附加知识点: 科里化:多参数函数抓换成单参数3、计算var a = [function(x) { return x * *;}, 20];计算 a[0](a[1]) 的值;答案是 400; 判断一个对象是否是数组12345678910111213141516171、ES 5中 Array.isArray(对象)2、自己写isArrayvar isArray = Function.isArray || function(o) { return typeof o === 'object' && Object.prototype.tostring.call(o) === '[object Array]'}3、instanceof操作符检测对象的原型链是否指向构造函数的prototype对象的var arr = [1,2,3,1]; alert(arr instanceof Array); // true4、对象的constructor属性除了instanceof,每个对象还有constructor的属性,利用它似乎也能进行Array的判断。var arr = [1,2,3,1]; alert(arr.constructor === Array); // true 如何根js据脚本检查某个样式浏览器是否支持,如 textShadow12345678910111213141516171819202122232425262728293031323334核心思路var root = document.documentElement;if ('textShadow' in root.style) { root.classList.add('textShadow');} else { root.classList.add('no-textShadow');}检查方法function testProp(property) { var root = document.documentElement; if(property in root.style) { root.classList.add(property.toLowerCase()); return true; } root.classList.add('no-' + property.toLowerCase()); return false;}* 能解析某个css特性,不代表它已经实现(或正确实现)了这个特性!把样式放进元素中function testValue(id, value, property) { var testElement = root.createElement('p'); testElement.style[property] = value; if(testElement.style[property]) { root.classList.add(id); return true; } root.classList.add('no-' + id); return false;} 函数名 和 变量重名会怎样,为什么如果变量名 和函数拥有相同的名称12345678910111213141516171819var a = 100;function a (){ console.log('function a');}a(); // TypeError: a is not a function这是为什么呢:因为在js解析的过程中,1、变量的申明和\b函数的申明会提升到顶部2、函数的申明在最前面,接着是变量3、申明和赋值是拆分开的4、变量的赋值会覆盖函数的声明js解析过程如下:var a = function (){ console.log('function a')}var a = 100;a(); #### 1234567var string = "我的账户余额:2,235,467.20";// 请用js计算出我到底有多少钱(输出Number类型数字,代码尽量简洁,考虑通用情况)-------------// 使用正则表达式出\b金额数字,然后再将金额数字中的‘,’,替换掉/^(([1-9]\\d*)|0)(\\.\\d{1,2})?$/ 原型链闭包css多重边框的实现1234561、使用多重元素模拟边框(差)2、使用css box-shadow (优) box-shadow: 0 0 0 10px #655, 0 0 0 15px deeppink, 0 2px 5px 15px rgba(0,0,0,.6); 开放性问题混合应用的优势\b初 中 高级工程师怎么\b区分 理解。有一个新的工程 新的项目,你要怎么建立相关架构某公司前端面试试题函数式编程理解 (Keep Learning Keep Writing……)","tags":[]},{"title":"css3原生变量申明和使用","date":"2016-11-27T16:05:06.000Z","path":"28/11/css3-primary-variable/","text":"虽然sass、less或者刚出的Stylus这些预编译的css的出现,让我们前端开发变得更方便和简洁。但在一定层度上有增加了工程的复杂度,前端现在百花齐放,各种技术和工具的出现让人眼花缭乱。我个人看法是技术在需要的时候用,不要只为技术而技术。尽量保持工程的单一。所以看到这个css原生的变量出现,有点小激动。 原文 介绍变量的定义 可以让我们在错杂庞大的css中抽象出一个便于维护和使用的对象。 使用1234变量定义: --*使用变量: var(--*)命名规范: 不能出现 { } [ ] ; ! % $等特殊字符。命名还是比较宽松的,可以为数字、字母、横线、下滑线或者中文等组成。ps:css里面是不区分大小写的,但是定义变量的时候可以使用大写,建议还是根据css的规范全都使用小写。 所以css变量定义 也分全局和局部 全局变量: 定义在 body {} 或者 :root{} 里面 局部变量: 定义在你需要定义的父节点选择器上 例如:div.class1{}里面。 不用太纠结上面的概念性,直接看下面的例子就好 用例本例子因为使用markdown编译 会把–符号做特除处理,所以为方便大家直观的理解,样式直接写在行内。 原生变量的使用,已使用在微信小程序上测试使用,虽然很方便,但是只在IOS上能完美兼容,在大部分android手机上还是有问题,使用在生产上还需谨慎。 例子一在根节点上定义全局变量,变量全局可用 12345678:root { --main-color: #06c; --accent-color: #006;}/* The rest of the CSS file */#foo h1 { color: var(--main-color);} 例子二变量定义 区分 大小写 12345678910111213141516171819202122<style> div { color: #000; --foo: red; --FOO: #ff5073; } .theLineColor { color: var(--foo); } .secondColor { color: var(--FOO); }</style><body> <div class="theLineColor"> aaaaaaa </div> <div dir="" class="secondColor"> bbbbb </div></body> 运行结果: .root22 div { color: #000; –foo: red; –FOO: #ff5073; } .theLineColor { color: var(–foo); } .secondColor { color: var(–FOO); } aaaaaaa bbbbb 例子三1--foo: if(x > 5) this.width = 10; While this value is obviously useless as a variable, as it would be invalid in any normal property, it might be read and acted on by JavaScript. 反正我是没闹明白官文里面是几个意思,知道怎么使用的可以留个言告诉我下 例子四继承父类选择器的样式的定义 1234567:root { --header-color: #06c;}h1 { background-color: var(--header-color);} 例子五优先级顺序,和css的选择器的优先级一样 1234567891011:root { --color: purple; }div { --color: green; }#alert { --color: red; }* { color: var(--color); }<p>我的紫色继承于根元素</p><div>我的绿色来自直接设置</div><div id='alert'> ID选择器权重更高,因此阿拉是红色! <p>我也是红色,占了继承的光</p></div> .root5 { –color: purple; } .root5 div { –color: green; } #alert { –color: red; } .root5 * { color: var(–color); }我的紫色继承于根元素我的绿色来自直接设置 ID选择器权重更高,因此这行是红色! 我也是红色,占了继承的光 例子六变量可以根据不同语言单独保存,对需要国际化的网站很方便 1234567:root,:root:lang(en) {--external-link: "external link";}:root:lang(de) {--external-link: "externer Link";}a[href^="http"]::after {content: " (" var(--external-link) ")"}<div class="root2"><a href="http://www.meiyou.com">美柚</a></div> 默认会出现 美柚(external link).root2,.root2:lang(en) { –external-link: “external link”; }.root2:lang(de) { –external-link: “externer Link”; }a[href^=”http”]::after { content: “ (“ var(–external-link) “)”; }美柚 例子七循环依赖 1234:root { --main-color: #c06; --accent-background: linear-gradient(to top, var(--main-color), white);} 例子八没有 任何作用 的互相引用,而且他们计算的都是个初始数值 1234:root { --one: calc(var(--two) + 20px); --two: calc(var(--one) - 20px);} 例子九变量的计算和引用 1234<one><two><three /></two></one>one { --foo: 10px; }two { --bar: calc(var(--foo) + 10px); }three { --foo: calc(var(--bar) + 10px); } 例子十这是个 错误 的定义例子,变量的定义不能在属性名上 1234.foo { --side: margin-top; var(--side): 20px;} 例子十一在组件中使用,可以覆盖新想要覆盖的变量属性。可以灵活应用于组件中。 12345678910111213141516171819202122/* In the component’s style: */.component .header { color: var(--header-color, blue);}.component .text { color: var(--text-color, black);}/* In the larger application’s style: */.component { --text-color: #080; /* header-color isn’t set, and so remains blue, the fallback value */}<div class="component"> <div class="header">header </div> <div class="text">text</div> <div>component</div></div> \b#### 响应式使用例子 在复杂的响应式布局中也可以使用变量的定义,根据不同分辨率的环境,设置不同的变量参数,达到相应变化的目的 张鑫旭的响应式例子 123456789101112131415161718192021.box { --columns: 4; --margins: calc(24px / var(--columns)); --space: calc(4px * var(--columns)); --fontSize: calc(20px - 4 / var(--columns));}@media screen and (max-width: 1200px) { .box { --columns: 3; }}@media screen and (max-width: 900px) { .box { --columns: 2; }}@media screen and (max-width: 600px) { .box { --columns: 1; }} 兼容性兼容性是绿油油的片 ps: 这是编辑草稿的公开副本。它仅供讨论,并可随时更改。其在这里的出版并不意味着W3C认可其内容。 官方文档","tags":[{"name":"css","slug":"css","permalink":"http://www.lixingdecai.com/tags/css/"}]},{"title":"敏捷开发玩旅游--福建霞浦.大嵛山岛","date":"2016-11-27T05:45:16.000Z","path":"27/11/mytravel-yushandao/","text":"学以致用-写攻略周三提出需求,周六成功实施上线,快速迭代设计修改,各个节点之间松散耦合,互联网的开发速度。周日晚上开心回到家 两个小时手打攻略 附图有山有海有有草原 有摄影师最爱的滩涂 安静美丽的夜晚渔村 当然 还有主角","tags":[{"name":"旅游","slug":"旅游","permalink":"http://www.lixingdecai.com/tags/旅游/"}]},{"title":"重新学习Promise对象","date":"2016-11-20T15:52:58.000Z","path":"20/11/learn-more-promise/","text":"最早接触Promise的时候是在jquery,当时看的懵懵懂懂,没有去深入研究,只处于知道怎么用的阶段。现在在写微信小程序的时候发现不能使用ES6中的Promises,才发现自己知识的薄弱,查查资料,深度全面的了解下Promise。 简介Promise:用来传递异步操作的对象。作为一个异步编程的一种解决方案而生。Promise的中文是承诺,对未来发生的许诺。成功会怎样,失败了又会返回什么。 其实在很早,Promise就实现了。我接触它的时候是jquery(1.5)中$.Deferred.Promise()创建promise对象,JQuery的ajax返回的就是一个deferred对象(deferred 和Promise很容易搞混)。 为什么选择 因为使用简单,提供统一的接口来操作异步。代码可读性强,使用类似同步操作的方式操作异步过程,避免了地狱般回调函数的层层嵌套。莫急 后面代码有详细例子。 ES6 Promise而ES6只是将其写进语言标准,统一了用法,并原生的提供了Promise对象。 三种状态Pending(进行中)、Resolved(已完成)、Rejected(已失败) Api & 实战 Promise.resolve() // 成功返回 Promise.reject() // 失败返回 Promise.prototype.then() Promise.prototype.catch() Promise.all() // 所有的完成 var p = Promise.all([p1,p2,p3]); Promise.race() // 竞速,完成一个即可 传统callback 回调思路: 12345678910111213141516地狱般嵌套:asyncFunc1(function(){ //... asyncFunc2(function(){ //... asyncFunc3(function(){ //... asyncFunc4(function(){ //... asyncFunc5(function(){ //... ... }); }); }); });}); 或者你觉得可以稍微优雅点的地狱 123456789101112asyncFunc1(){ setTimeout(asyncFunc2, 2000);}asyncFunc2(){ setTimeout(asyncFunc3, 2000);}asyncFunc3(){ setTimeout(asyncFunc3, 2000);}asyncFunc4(){ console.log('asyncFunc4 complete!');} 而引用promise的链式处理异步后,代码可读性会强,逻辑会更清晰: 12345678910function asyncFunc1(){ return new Promise(function (resolve, reject) { //... })}asyncFunc1() .then(asyncFunc2) .then(asyncFunc3) .then(asyncFunc4) .then(asyncFunc5); 典型错误(我曾经也犯过这样的错误): 12345678910111213new Promise(function(res, rej) { console.log(Date.now() + " start setTimeout 1"); setTimeout(res, 2000);}).then(function() { console.log(Date.now() + " timeout 1 call back"); new Promise(function(res, rej) { console.log(Date.now() + " start setTimeout 2"); setTimeout(res, 3000); }).then(function() { console.log(Date.now() + " timeout 2 call back"); })});这样子就陷入无限嵌套的噩梦之中,就不是我们要的promise了。 then函数的onFulfilled(onCompleted)回调函数会返回一个新的Promise变量,你可以再次调用这个新的Promise变量的then函数 但是问题来了,如果多个异步嵌套中有个方法返回错误(reject)了,promise将会如何处理 将要如何处理。看代码: 12345678var promise3 = new Promise((resolve, reject) => { reject("this is promise3 reject catch");}).then((msg) => { console.log('1' + msg);}).catch((err) => { console.log('2' + err);});//console: 2this is promise3 reject catch 当如果多异步嵌套中有一个请求返回错误,会直接往外抛,在catch中被拦截,而多嵌套异步请求将停止。 隐式包装Promise:在第一个 then中使用 return来返回一个 string, 而不是用 resolve或者 reject,效果其实是一样的。当然不只是 string 也可以直接 return Object等。 123456789101112131415161718192021var promise = new Promise((resolve, reject) => { var promise = new Promise((resolve, reject) => { console.log("promise starts"); setTimeout(() => { resolve("this is promise resolve"); }, 2000); }); resolve(promise);}).then((msg) => { console.log('msg: ' + msg); return "promise .then()隐式包装resolved Promise";}, (err) => { console.log(err);}).then((word) => { console.log(word);});------ console.log -------promise startsmsg: this is promise resolvepromise .then()隐式包装resolved Promise 显示包装Promise:在then中返回一个Promise对象 12345678910111213141516171819202122232425262728var promise = new Promise((resolve, reject) => { console.log("promise starts1"); var promise = new Promise((resolve, reject) => { console.log("promise starts2"); setTimeout(() => { resolve("this is promise resolve"); }, 2000); }); console.log("promise starts3"); resolve(promise);}).then((msg) => { console.log("promise starts4"); console.log('msg: ' + msg); return Promise.resolve("promise .then()显式包装resolved Promise");}, (err) => { console.log(err);}).then((word) => { console.log(word);});---- console log ------promise starts1promise starts2promise starts3undefinedpromise starts4msg: this is promise resolvepromise .then()显式包装resolved Promise Promise.all的 123456789101112131415161718192021222324252627282930var promise6 = new Promise((resolve, reject) => { var promiseArr = []; for (var i = 0; i < 5; ++i) { promiseArr.push(new Promise((resolve, reject) => { console.log(`promise6_${i}starts`); ((index) => { setTimeout(() => { console.log(`before promise6_${index} resolved`); resolve(`this is promise6_${index} resolve`); }, index * 1000); })(i); })); } resolve(Promise.all(promiseArr));}).then((msgArr) => { console.log(`promise6 all resolved ${msgArr}`);});//运行结果//promise6_0 starts//promise6_1 starts//promise6_2 starts//promise6_3 starts//promise6_4 starts//before promise6_0 resolved//before promise6_1 resolved//before promise6_2 resolved//before promise6_3 resolved//before promise6_4 resolved//promise6 all resolved this is promise6_0 resolve,this is promise6_1 resolve,this is promise6_2 resolve,this is promise6_3 resolve,this is promise6_4 resolve 异常处理的相关内容比较少 参考自http://www.codesec.net/view/493391.html 兼容性东西是很好用 但是兼容性太差。比如微信小程序就无法使用。也是因此让重新学习Promise的动机.兼容性如下图: 解决方案(小程序)用polyFill的解决。也就是自己引用第三方库,类似Q、When.js、 bluebird(26.7kb) 等。而且听说第三方库的效率会更高。 12345678910111213141516171819var Promise = require('../libs/bluebird.min') //我用了bluebird.jsfunction wxPromisify(fn) { return function (obj = {}) { return new Promise((resolve, reject) => { obj.success = function (res) { resolve(res) } obj.fail = function (res) { reject(res) } fn(obj) }) }}module.exports = { wxPromisify: wxPromisify} 使用 1234567891011121314var util = require('../utils/util')var getLocationPromisified = util.wxPromisify(wx.getLocation)getLocationPromisified({ type: 'wgs84'}).then(function (res) { var latitude = res.latitude var longitude = res.longitude var speed = res.speed var accuracy = res.accuracy}).catch(function () { console.error("get location failed")}) 小程序兼容性参考自https://segmentfault.com/a/1190000007392283 Promiseの缺点 无法取消。一旦新建就会执行,没方法取消 当处于Pending(进行中)状态的时候,无法得知最近进展到哪个阶段","tags":[{"name":"ES6","slug":"ES6","permalink":"http://www.lixingdecai.com/tags/ES6/"}]},{"title":"My New Post","date":"2016-10-12T07:47:44.000Z","path":"12/10/My-New-Post/","text":"","tags":[]}]