关于chrome:Chrome-80之后-iframe不支持发送第三方cookie的问题

最近在我的项目中遇到了一个问题,我的项目里有一个受权页面是在快手页面进行受权的,这个受权页面放在了iframe当中来做。客户反馈关上受权页面之后,快手间接进入登录界面,而且在里面的页面曾经登录的也被革除掉登录状态进入登录页面了。 问题剖析首先在本人的页面点击受权发现没有问题,在共事的电脑上却呈现同样的问题。而且都是chrome 84,win10零碎。 发现在控制台有这样几条信息: A cookie associated with a cross-site resource at http://kuaishou.com/ was set without the `SameSite` attribute. It has been blocked, as Chrome now only delivers cookies with cross-site requests if they are set with `SameSite=None` and `Secure`. You can review cookies in developer tools under Application>Storage>Cookies and see more details at https://www.chromestatus.com/feature/5088147346030592 and https://www.chromestatus.com/feature/5633521622188032.{loginUrl: "https://ad-login.e.kuaishou.com?sid=kuaishou.ad.ds…owUrl%3Dhttp%253A%252F%252Fad.e.kuaishou.com%252F", result: 109, error_msg: "网络连接失败,请刷新以后页面。"}看到快手在受权中应用了不通的几个域名,而后在外面获取不到登录信息。想起来2月份看到说chrome不反对第三方cookie的事件。然而还不能确定,因为在我的电脑上也有这条信息。 搜了搜iframe外面怎么设置反对第三方cookie获取的办法,然而没有找到。 只能是服务端设置:SameSite=None; Secure 才能够。因为是第三方的页面,所以也搞不了。 ...

August 1, 2020 · 1 min · jiezi

关于chrome:Chrome-80之后-iframe不支持发送第三方cookie的问题

最近在我的项目中遇到了一个问题,我的项目里有一个受权页面是在快手页面进行受权的,这个受权页面放在了iframe当中来做。客户反馈关上受权页面之后,快手间接进入登录界面,而且在里面的页面曾经登录的也被革除掉登录状态进入登录页面了。 问题剖析首先在本人的页面点击受权发现没有问题,在共事的电脑上却呈现同样的问题。而且都是chrome 84,win10零碎。 发现在控制台有这样几条信息: A cookie associated with a cross-site resource at http://kuaishou.com/ was set without the `SameSite` attribute. It has been blocked, as Chrome now only delivers cookies with cross-site requests if they are set with `SameSite=None` and `Secure`. You can review cookies in developer tools under Application>Storage>Cookies and see more details at https://www.chromestatus.com/feature/5088147346030592 and https://www.chromestatus.com/feature/5633521622188032.{loginUrl: "https://ad-login.e.kuaishou.com?sid=kuaishou.ad.ds…owUrl%3Dhttp%253A%252F%252Fad.e.kuaishou.com%252F", result: 109, error_msg: "网络连接失败,请刷新以后页面。"}看到快手在受权中应用了不通的几个域名,而后在外面获取不到登录信息。想起来2月份看到说chrome不反对第三方cookie的事件。然而还不能确定,因为在我的电脑上也有这条信息。 搜了搜iframe外面怎么设置反对第三方cookie获取的办法,然而没有找到。 只能是服务端设置:SameSite=None; Secure 才能够。因为是第三方的页面,所以也搞不了。 ...

August 1, 2020 · 1 min · jiezi

关于chrome:高级前端开发进阶指南Google-V8一事件循环

前言晚期浏览器的页面是运行在 UI线程 上的,为了在页面中引入JavaScript,不便JS操作DOM,JS也须要运行在和页面雷同的线程中,所以JS是单线程的。 一、基本概念事件循环系统由主线程、调用栈、宏工作、微工作、音讯队列等形成。 主线程:UI线程调用栈:一种数据结构、用来治理在主线程上执行的函数的调用关系音讯队列:用于寄存期待主线程执行的宏工作 ‘事件’列表 工作:UI线程每次从音讯队列中取出事件、执行事件的过程称为一次工作宏工作:音讯队列中期待被主线程执行的事件、宏工作蕴含鼠标、键盘、触控板事件微工作:一个须要异步执行的函数、执行的机会在主线程执行完结之后、以后宏工作完结之前 常见宏工作有:主js、UI渲染、setTimeout、setInterval、setImmediately、requestAnimationFrame、I/O等 常见微工作有:process.nextTick()、promise.then()(new Promise不算!)、Object.observe()等 二、事件循环生命周期=> 初始化 1、从音讯队列中取出工作2、全局执行上下文压入调用栈中3、在全局上下文中创立微工作队列=> 执行工作 事件执行中:1、减少新的上下文到调用栈中2、执行函数中的代码3、封装新的事件并增加到音讯队列中事件执行后:1、在函数执行完结后将以后函数的执行上下文从调用栈中弹出2、查问并执行全局上下文中的微工作队列3、垃圾回收?=> 完结以后事件 从音讯队列中取出新的事件开始执行、周而复始图文解说备注:本文章局部图片来自 《极客工夫:图解 Google V8》,如有侵权,请告知删除,感激! 用以下代码为例,了解事件循环机制:function foo() { console.log('setTimeout star'); out && out(); console.log('Promise star'); pro && pro(); console.log('bar star'); bar && bar();}function bar() { console.log('bar');}function pro() { Promise.resolve().then(res => { console.log('Promise'); });}function out() { setTimeout(function() { console.log('setTimeout:'); }, 100);}foo();从音讯队列中取出foo()事件创立调用栈并将全局执行函数上下文压入栈中:将foo函数执行上下文压入栈中:执行console.log('setTimeout star');:将out函数执行上下文压入栈中:将setTimeout的回调函数封装成一个新的事件100ms后增加到音讯队列中:out函数执行完结、将out函数上下文从调用栈弹出:执行console.log('Promise star');:将pro函数执行上下文压入栈中:将微工作增加到调用栈中全局执行上下文的微工作队列中:pro函数执行完结、将pro函数上下文从调用栈弹出:执行console.log('bar star');:将bar函数执行上下文压入栈中:执行console.log('bar');:bar函数执行完结、将bar函数上下文从调用栈弹出从全局执行函数上下文中将微工作队列中得函数取出,执行console.log('Promise');完结以后事件、当从setTimeout事件增加到音讯队列后取出事件,执行console.log('setTimeout'); 三、常见关联问题堆栈溢出function foo() { foo();}foo()上述代码中foo函数中调用了本身,依据下面咱们理解的事件循环机制,咱们会发现在执行foo函数的过程中,主线程会一直的向调用栈中压入foo函数的执行上下文,而因为foo函数始终没有执行完结,所以函数上下文并不会从调用栈中移除,然而调用栈的容量是无限的,所以就会造成调用栈的溢出。 面对此类问题,咱们有两种解决方案:1、宏工作异步调用 function foo() { setTimeout(function() { foo(); }, 0);}// 这里间接给出代码,能够根据上述内容分析为什么这样就不会造成堆栈溢出(我是不会抵赖本人懒得写了~)// 另外须要留神,即使这样能够不造成堆栈溢出,但咱们仍旧不举荐这样写,大量的事件阻塞了音讯队列中其余事件的执行2、按条件完结调用——递归函数 ...

July 24, 2020 · 1 min · jiezi

关于chrome:高级前端开发进阶指南Google-V8一事件循环

前言晚期浏览器的页面是运行在 UI线程 上的,为了在页面中引入JavaScript,不便JS操作DOM,JS也须要运行在和页面雷同的线程中,所以JS是单线程的。 一、基本概念事件循环系统由主线程、调用栈、宏工作、微工作、音讯队列等形成。 主线程:UI线程调用栈:一种数据结构、用来治理在主线程上执行的函数的调用关系音讯队列:用于寄存期待主线程执行的宏工作 ‘事件’列表 工作:UI线程每次从音讯队列中取出事件、执行事件的过程称为一次工作宏工作:音讯队列中期待被主线程执行的事件、宏工作蕴含鼠标、键盘、触控板事件微工作:一个须要异步执行的函数、执行的机会在主线程执行完结之后、以后宏工作完结之前 常见宏工作有:主js、UI渲染、setTimeout、setInterval、setImmediately、requestAnimationFrame、I/O等 常见微工作有:process.nextTick()、promise.then()(new Promise不算!)、Object.observe()等 二、事件循环生命周期=> 初始化 1、从音讯队列中取出工作2、全局执行上下文压入调用栈中3、在全局上下文中创立微工作队列=> 执行工作 事件执行中:1、减少新的上下文到调用栈中2、执行函数中的代码3、封装新的事件并增加到音讯队列中事件执行后:1、在函数执行完结后将以后函数的执行上下文从调用栈中弹出2、查问并执行全局上下文中的微工作队列3、垃圾回收?=> 完结以后事件 从音讯队列中取出新的事件开始执行、周而复始图文解说备注:本文章局部图片来自 《极客工夫:图解 Google V8》,如有侵权,请告知删除,感激! 用以下代码为例,了解事件循环机制:function foo() { console.log('setTimeout star'); out && out(); console.log('Promise star'); pro && pro(); console.log('bar star'); bar && bar();}function bar() { console.log('bar');}function pro() { Promise.resolve().then(res => { console.log('Promise'); });}function out() { setTimeout(function() { console.log('setTimeout:'); }, 100);}foo();从音讯队列中取出foo()事件创立调用栈并将全局执行函数上下文压入栈中:将foo函数执行上下文压入栈中:执行console.log('setTimeout star');:将out函数执行上下文压入栈中:将setTimeout的回调函数封装成一个新的事件100ms后增加到音讯队列中:out函数执行完结、将out函数上下文从调用栈弹出:执行console.log('Promise star');:将pro函数执行上下文压入栈中:将微工作增加到调用栈中全局执行上下文的微工作队列中:pro函数执行完结、将pro函数上下文从调用栈弹出:执行console.log('bar star');:将bar函数执行上下文压入栈中:执行console.log('bar');:bar函数执行完结、将bar函数上下文从调用栈弹出从全局执行函数上下文中将微工作队列中得函数取出,执行console.log('Promise');完结以后事件、当从setTimeout事件增加到音讯队列后取出事件,执行console.log('setTimeout'); 三、常见关联问题堆栈溢出function foo() { foo();}foo()上述代码中foo函数中调用了本身,依据下面咱们理解的事件循环机制,咱们会发现在执行foo函数的过程中,主线程会一直的向调用栈中压入foo函数的执行上下文,而因为foo函数始终没有执行完结,所以函数上下文并不会从调用栈中移除,然而调用栈的容量是无限的,所以就会造成调用栈的溢出。 面对此类问题,咱们有两种解决方案:1、宏工作异步调用 function foo() { setTimeout(function() { foo(); }, 0);}// 这里间接给出代码,能够根据上述内容分析为什么这样就不会造成堆栈溢出(我是不会抵赖本人懒得写了~)// 另外须要留神,即使这样能够不造成堆栈溢出,但咱们仍旧不举荐这样写,大量的事件阻塞了音讯队列中其余事件的执行2、按条件完结调用——递归函数 ...

July 24, 2020 · 1 min · jiezi

Chrome-8485-的三个不兼容更新CLodop-中招跨站-SSO-和-第三方-cookie-会是重灾区

TLS 1.0 and TLS 1.1 政策变更告诉:https://chromestatus.com/feat...告诉内容: In M-84, Chrome will show a full page interstitial warning on sites that do not support TLS 1.2 or higher.翻译下,即 在 Chrome 84 里,chrome 会对不反对 TLS1.2 的站点,插入一个正告简要解释下,对于 https 的链接,其中的平安层协定是基于 TLS 的,以后的不少站点,在服务器的配置都是 TLS1.2(十年前就进去了)及以上的,然而也有局部遗留站点是基于 TLS1.0 和 1.1 的,而 TLS1.0 和 1.1 又有不少安全漏洞,思考到基于 TLS1.0 和 1.1 的链接占比只有 0.5%,所以 chrome 感觉当初废除的机会到了。 影响范畴基于 TLS1.0 和 1.1 的站点,如果你在 chrome 84 里间接拜访可能会这样 如果你有申请这样的脚本文件,天然会申请失败。 实际上,如果你的 chrome 在 72 以上,最好是靠近 84,那你当初就能在管制台上看到这样的正告 ...

July 12, 2020 · 1 min · jiezi

Chrome-的这个功能可以检查你的密码是否泄露

技术编辑:徐九丨发自 思否编辑部 熟练运用 Chrome 扩展程序的朋友,应该都知道谷歌曾引入过一个密码检查的扩展,以便用户检查密码是否被泄露,并且还能检测并检测我们的用户名和密码是否因为在某些网站或者应用程序上使用从而被黑客窃取。 为了进一步方便用户使用,谷歌将这项功能集成到了名为「密码泄露检测」的 Chrome 密码管理器中。 如何检测密码是否被泄露 使用 Google 账户登录 Chrome 后,进入浏览器的设置界面,点击「安全检查」中的「立即检查」按钮,即可自动检测密码是否被泄露。 如果出现泄露的情况,点击查看即可了解具体是那些平台的账号和密码被泄露。 密码检查的技术原理Google 在设计「密码检查」时充分考虑了隐私权问题。该功能不会报告有关我们的帐号、密码或设备的任何识别信息。但会报告与显示不安全凭据的查询次数以及所涉网域相关的匿名信息,以提高网站的覆盖率。 根据官方的说明文档,我们整理出密码安全检查功能会存储以下信息: 扫描到的使用不安全密码的登录次数;如果密码安全检查发现输入的密码和用户名不安全,则会生成针对相应信息的经过哈希处理的部分代码,并将此部分代码存储到我们的 Chrome 浏览器中。不过他人无法利用此部分代码重新创建我们的信息的完整版本;感兴趣的朋友可以访问 https://support.google.com/ac...,详细了解“密码检查”的工作原理。

July 5, 2020 · 1 min · jiezi

谷歌浏览器调试工具vuedevtools不显示

调试器安装GitHub下载安装git clone https://github.com/vuejs/vue-devtools 安装依赖和打包进入目录 cd vue-devtools安装依赖 npm i 或 cnpm i (npm较慢)打包 npm run build在vue-devtools文件夹下:shells>chrome>manifest.json,将配置里的persistent的值修改为true设置进入谷歌的扩展程序 -》 开启开发者模式 -》 加载已解压的扩展程序 -》 选择“vue- devtools>>shells>>chrome” ,将chrome文件夹导入 ,完成即可。 配置好了以后,控制台如果还没有vue选项,就在代码 main.js 文件 写入以下代码 Vue.config.devtools = true;

June 29, 2020 · 1 min · jiezi

CSS-关于背景渐变和自动全屏

CSS 关于背景渐变和自动全屏主编在css开发时发现了一个致命的问题:在设置了背景颜色渐变后好不容易调成了全屏覆盖但按下了F11的时候崩溃的世界开始了所以这篇文章主要介绍CSS背景渐变色和自动全屏适应背景渐变色本文只介绍线性渐变背景渐变相信大家也都不陌生先看下图小编配的这个色也还可以哈 代码如下body{ background-image: -webkit-linear-gradient(60deg,rgba(218, 169, 215, 0.637),rgba(128, 174, 235, 0.904)); //60deg代表渐变色的角度 大家可以自己试试看 //渐变色便是后面两个配色的结果 当然也可以设置第三个}背景全屏上面大家也看到了渐变背景没有全屏 这样也是很影响美观了但这时候肯定有人说 小编你没设置宽高啊 好那我们就来一个宽高看看效果body{ background-image:-webkit-linear-gradient(60deg,rgba(218, 169, 215, 0.637),rgba(128, 174, 235, 0.904)); min-height:648px;}效果如下:那么问题来了 当我按下F11最大化窗口的时候:显然问题并没有彻底解决那么下面为各位奉上自适应屏幕代码 body{ background-image:-webkit-linear-gradient(60deg,rgba(218, 169, 215, 0.637),rgba(128, 174, 235, 0.904)); background-position: center 0; background-repeat: no-repeat; background-attachment: fixed; background-size: cover; -webkit-background-size: cover; -o-background-size: cover; -moz-background-size: cover; -ms-background-size: cover;}//小编测试了谷歌浏览器和星愿浏览器 都是可以自动适配的//大家可以带回去多做实验效果图如下: 好了 本文的内容就到这里了希望主编有帮到你

June 22, 2020 · 1 min · jiezi

小技巧Chrome-将网页加入-Apps-快捷打开

平时常用的工具类网页、SPA 应用(Single Page Application),还在打开浏览器、再找书签么? Chrome 可以帮您安装快捷图标,直接双击打开就好了。 Chrome Apps打开 Chrome 浏览器,输入 chrome://apps ,即可打开应用页面: 还可以选择在系统应用里安装快捷图标, macOS 如下: 以后,这些常用网页,就可以直接双击打开了。 安装一个 Chrome AppStep 1. Chrome 打开某个网页,如: https://simpleicons.org Step 2. Chrome 右上角「More」,选择「More Tools」,再选择「Create Shortcut」 即会弹出如下对话框。 Step 3. 勾选「Open as window」,允许独立窗口打开网页。然后「Create」 Step 4. Chrome Apps 里就会新增一个应用图标,可双击打开 这样,就可以将常用网页整理到一个 Chrome Apps 页面里了。 Step 5. 系统应用里也会创建一个它的快捷图标,可双击打开 macOS 如下: Step 6. 双击快捷图标,打开这个 Chrome App 试试看 是个独立窗口呢。 结语Q: Windows 桌面建立一个个网页快捷方式,不是一样的么? ...

June 20, 2020 · 1 min · jiezi

HTTP-请求头各参数具体含义

作为前端开发,了解浏览器发送http请求是很有必要的。HTTP请求的7个步骤1.建立TCP链接 2.浏览器发送请求(GET/sample/hello.jsp HTTP/1.1) 3.浏览器发送请求头(request header) 4.服务器发送应答(HTTP/1.1 200 OK) 5.服务器发送应答头(response header) 6.服务器发送数据 7.服务器关闭TCP连接 浏览器中,network的请求信息以及header的每一项代表什么意思General部分: Request URL : 资源的请求url Request Method : HTTP方法 Status Code : 响应状态码 200(状态码) OK(原因短语) 301 - 资源(网页等)被永久转移到其它URL 404 - 请求的资源(网页等)不存在 500 - 内部服务器错误 Response Headers:Content-Encoding:gzip ——压缩编码类型 Content-Type:text/html ——服务端发送的类型及采用的编码方式 Date:Tue, 14 Feb 2017 03:38:28 GMT ——客户端请求服务端的时间 Last-Modified:Fri, 10 Feb 2017 09:46:23 GMT ——服务端对该资源最后修改的时间,GMT是格林尼治标准时间 Server:nginx/1.2.4 ——服务端的Web服务端名 Transfer-Encoding:chunked ——分块传递数据到客户端 Request Headers:Accept:text/html ——客户端能接收的资源类型 Accept-Encoding:gzip, deflate ——客户端能接收的压缩数据的类型 Accept-Language:en-US,en;q=0.8 ——客户端接收的语言类型 ...

June 3, 2020 · 1 min · jiezi

渲染性能分析下

上篇我们大致分析了在处理JavaScript阶段和Style阶段需要注意的问题,这篇我们就来看下在Layout、Paint、Composite阶段以及处理用户行为的时候,应该关注的问题所在。 避免大型的复杂的布局和布局限制Layout阶段浏览器将计算元素的大小,在页面中的位置,其他元素的影响等等,与样式计算(Style calculation)类似,基本限制因素如下: 需要Layout的元素数量Layout的复杂度TL;DR Layout适用于整个文档流DOM的数量直接影响Layout的性能消耗,尽量避免触发Layout避免强制同步修改Layout,造成反复Layout。即读取style的值然后修改style尽可能的避免触发Layout当更改样式时,浏览器会去检查需不需重新计算触发Layout,一般来说修改元素的几何属性(geometric properties)例如:宽高,布局定位都会触发Layout .box { width: 200px; height: 200px;}// 改变元素宽高 触发Layout.box-expanded: { width: 300px; height: 300px;}Layout是作用于全局整个文档流的,所以如果有大量的元素需要处理,就会消耗很长时间去计算这些元素的大小和定位。如果无法避免触发Layout,可以通过Performance查看Layout阶段的耗时是否是影响性能的瓶颈。 在Performance中我们可以清楚的看到Layout阶段消耗的时间,以及涉及的节点数(如图为314个元素)https://csstriggers.com/ 列出了一些CSS属性会触发渲染的哪个阶段,可以作为对照参考。另外使用flexbox布局要比传统的通过float或者相对定位绝对定位实现布局更快。 避免出现强制同步布局正常情况下渲染步骤是先执行JavaScript,然后是style calculation 然后触发Layout。但是有种情况是触发Layout的时间点早于JavaScript的执行,这种情况叫强制同步布局(forced synchoronous layout) 要明确的是在JavaScript运行时,前一帧的布局属性值都是已知的。举个例子来说如果你想在帧(frame)开始前获取某个元素的高度,就可以这样写: requestAnimtionFrame(logBoxHeight);function logBoxHeight(){ console.log(element.offsetHeight);}但是如果你先改变的元素的样式然后在获取元素高就会出问题 function logBoxHeight(){ element.classList.add('big'); console.log(element.offsetHeight);}现在的情况就变成这样,由于添加了新的class后要输入元素的offsetHeight,浏览器必须先重新进行布局计算才能拿到正确的offsetHeight的值,这完全是没必要的,而且这个例子中通常情况下都是不需要先去设置样式再去取属性值的,直接使用最后一帧的属性值完全足够了。所以一般情况下最好是先去读取需要的属性值,然后再做更改。 function logBoxHeight(){ console.log(element.offsetHeight); element.classList.add('big');}还有一种更糟糕的情况是反复不断的强制同步触发layout。看下面的代码 function resizeAllParagraphsToMatchBlockWidth(){ // 让浏览器陷入读写循环 for(let i = 0; i < paragraphs.length; i++){ paragraphs[i].style.width = element.offsetHeight + 'px'; }}打眼一看好像没什么问题,其实这种问题很常见每次迭代都会去读取element.offsetHeight属性,然后用它去更新paragraph的width属性。解决办法也很常见就是读取一次做一个缓存。 const width = element.offsetHeight;function resizeAllparagraphsToMatchBlockWidth(){ for(let i = 0; i < paragraphs.length;i++){ paragraphs[i].style.width = width + 'px'; }}简化Paint复杂度,减少Paint的面积Paint是一个填充像素(pixels)的过程,最终这些像素会通过合成器合成到屏幕。这个阶段通常是渲染元素整个过程中最消耗时间的阶段,所以要尽可能的避免 ...

November 3, 2019 · 1 min · jiezi

Chrome-快捷键概览

此文主要归纳 Chrome 中所有键盘快捷键的参考信息。一些快捷键全局可用,而其他快捷键会特定于 Chrome DevTools 中的单一面板。 它就像一本字典,可以随时查看我们需要的快捷键。 访问 DevTools访问 DevToolsMacWindows / Linux打开控制台面板Command + Option + JCtrl + Shift + J打开元素面板Command + Shift + C or Command + Option + CCtrl + Shift + C打开你上次使用的面板Command + Option+IF12 or Ctrl + Shift + IDevTools 跨面板快捷键全局快捷键MacWindows / Linux显示设置? or Function+F1? or F1显示下一个面板Command + ]Ctrl + ]显示上一个面板Command + [Ctrl + [根据历史切换 DevTools 的位置Command + Opt + [Ctrl + Shift + D打开/关闭 Device ModeCommand + Shift + MCtrl + Shift + M在当前文件或面板中搜索文本(不支持 Audits、Application、和 Security 面板)Command + FCtrl + F放大Command + Shift ++Ctrl ++缩小Command + Shift --Ctrl --恢复默认文本大小Command + 0Ctrl + 0打开/关闭 Command MenuCommand + Shift + PCtrl + Shift + P在所有加载的资源中搜索文本Command + Shift + FCtrl + Shift + F打开文件Command + OCtrl + O控制台快捷键控制台快捷键MacWindows / Linux拒绝命令提示建议EscapeEscape接受命令提示建议Right Arrow or TabRight Arrow or Tab输入历史中上/下一个命令向上键/向下键向上键/向下键聚焦到控制台Command + 反引号Ctrl + 反引号清除控制台Command + K or Option + LCtrl + L多行输入Command + ReturnShift + Enter执行ReturnEnterElements 面板快捷键Elements 面板MacWindows / Linux切换为以 HTML 形式编辑Function + F2F2撤消更改Command + ZCtrl + Z重新应用更改Command + Shift + ZCtrl + Y选择当前选定元素上方/下方的元素向上键/向下键向上键/向下键展开/折叠节点向右键/向左键向右键/向左键展开/折叠节点及其所有子节点Opt + 点击箭头图标Ctrl + Alt + 点击箭头图标编辑属性Enter / 双击属性Enter / 双击属性隐藏元素(visibility)HHStyles 边栏快捷键Styles 边栏MacWindows / Linux编辑规则点击点击插入新属性点击空格点击空格前往声明属性值的行Command + 点击属性Ctrl + 点击属性循环展示颜色值的 rbga、hsla 和 hex 形式按住 shift 键,然后单击值旁边的颜色预览框按住 shift 键,然后单击值旁边的颜色预览框编辑下一个/上一个属性Tab / Shift + TabTab / Shift + Tab以 0.1 为增量增大/减小值Opt + 向上键 / Opt + 向下键Alt + 向上键 / Alt + 向下键以 1 为增量增大/减小值向上键/向下键向上键/向下键以 10 为增量增大/减小值Shift + Up / Shift + DownShift + Up / Shift + Down以 100 为增量增大/减小值Command + Up / Command + DownCtrl + Up / Ctrl + DownSources 面板快捷键Sources 面板MacWindows / Linux暂停/继续执行脚本F8 or Command + \F8 or Ctrl + \跳过下一个函数调用F10 or Command + 'F10 or Ctrl + '进入下一个函数调用F11 or Command + ;F11 or Ctrl + ;跳出当前函数Shift + F11 or Command + Shift + ;Shift + F11 or Ctrl + Shift + ;暂停时继续执行某行代码按住 Command,然后单击代码行按住 Ctrl,然后单击代码行前往当前调用栈中当前帧下面的调用帧/帧上面的调用帧Control + . / Control + ,Ctrl + . / Ctrl + ,保存本地更改Command + SCtrl + S保存所有更改Command + Opt + SCtrl + Alt + S跳转到指定行(输入格式:单个数字)Control + GCtrl + G跳转到列(输入格式:行:列)Control + GCtrl + G在资源面板下搜索文件Command + O or Command + PCtrl + O or Ctrl + P关闭活动的标签Option + WAlt + W代码编辑器快捷键代码编辑器MacWindows / Linux跳转到匹配的括号Control + MCtrl + M从光标处删除至当前所在单词结尾Option + DeleteCtrl + Delete添加/删除行断点将光标集中在行上,然后按 Command + B将光标集中在行上,然后按 Ctrl + B切换注释Command + /Ctrl + /继续选择下一个匹配/撤消上一个选择Command + D / Command + UCtrl + D / Ctrl + U性能面板快捷键性能面板MacWindows / Linux开始/停止录制Command + ECtrl + E保存录制Command + SCtrl + S打开录制Command + OCtrl + O内存面板快捷键内存面板MacWindows / Linux开始/停止录制Command + ECtrl + E标签页和窗口快捷键标签页和窗口快捷键MacWindows / Linux打开新窗口Ctrl + N⌘ + N在无痕模式下打开新窗口Ctrl + Shift + N⌘ + Shift + N打开新的标签页,并跳转到该标签页Ctrl + T⌘ + T按标签页的关闭顺序重新打开先前关闭的标签页Ctrl + Shift + T⌘ + Shift + T跳转到下一个打开的标签页Ctrl + Tab 或 Ctrl + PgDn⌘ + Option + 向右箭头键跳转到上一个打开的标签页Ctrl + Shift + Tab 或 Ctrl + PgUp⌘ + Option + 向左箭头键跳转到特定标签页Ctrl + 1 到 Ctrl + 8⌘ + 1 到 ⌘ + 8跳转到最右侧的那个标签页Ctrl + 9⌘ + 9在当前标签页中打开主页Alt + Home⌘ + Shift + H打开当前标签页浏览记录中记录的上一个页面Alt + 向左箭头键⌘ + [ 或 ⌘ + 向左箭头键打开当前标签页浏览记录中记录的下一个页面Alt + 向右箭头键⌘ + ] 或 ⌘ + 向右箭头键关闭当前标签页Ctrl + w 或 Ctrl + F4⌘ + W关闭当前窗口Ctrl + Shift + w 或 Alt + F4⌘ + Shift + W最小化当前窗口Alt + 空格键,然后按 N 键⌘ + M最大化当前窗口Alt + 空格键,然后按 X 键⌘ + H退出 Google ChromeAlt + F,然后按 X 键⌘ + QGoogle Chrome 功能快捷键Google Chrome 功能快捷键MacWindows / Linux打开 Chrome 菜单Alt + F 或 Alt + E 显示或隐藏书签栏Ctrl + Shift + B⌘ + Shift + B打开书签管理器Ctrl + Shift + O⌘ + Option + B在新标签页中打开“历史记录”页Ctrl + H⌘ + Y在新标签页中打开“下载内容”页Ctrl + J⌘ + Shift + J打开 Chrome 任务管理器Shift + Esc 将焦点放置在 Chrome 工具栏中的第一项上Shift + Alt + T 将焦点放置在 Chrome 工具栏中最右侧的那一项上F10 将焦点移到未聚焦于的对话框(如果显示)或所有工具栏F6 打开查找栏搜索当前网页Ctrl + F 或 F3 跳转到与查找栏中搜索字词相匹配的下一条内容Ctrl + G 跳转到与查找栏中搜索字词相匹配的上一条内容Ctrl + Shift + G 打开“清除浏览数据”选项Ctrl + Shift + Delete⌘ + Shift + Delete在新标签页中打开 Chrome 帮助中心F1 使用其他帐号登录或以访客身份浏览Ctrl + Shift + M⌘ + Shift + M打开反馈表单Alt + Shift + I 地址栏快捷键地址栏快捷键MacWindows / Linux使用默认搜索引擎进行搜索输入搜索字词并按 Enter 键输入搜索字词并按 Enter 键使用其他搜索引擎进行搜索输入搜索引擎名称,然后按 Tab 键输入搜索引擎名称,然后按 Tab 键为网站名称添加 www. 和 .com,并在当前标签页中打开该网站输入网站名称并按 Ctrl + Enter 键输入网站名称并按 Control + Enter 键打开新的标签页并执行 Google 搜索输入搜索字词并按 Alt + Enter 键 跳转到地址栏Ctrl + L、Alt + d 或 F6⌘ + l从页面中的任意位置搜索Ctrl + K 或 Ctrl + E从地址栏中移除联想查询内容按向下箭头键以突出显示相应内容,然后按 Shift + Delete 键按向下箭头键以突出显示相应内容,然后按 hift + FN + Delete 键,在笔记本电脑上按 Forward Delete 或 Fn-Delete 键网页快捷键网页快捷键MacWindows / Linux打开选项以打印当前网页Ctrl + p⌘ + P打开选项以保存当前网页Ctrl + S⌘ + S重新加载当前网页F5 或 Ctrl + R 重新加载当前网页(忽略缓存的内容)Shift + F5 或 Ctrl + Shift + R⌘ + Shift + R停止加载网页Esc 浏览下一个可点击项TabTab浏览上一个可点击项Shift + TabShift + Tab显示当前网页的 HTML 源代码(不可修改)Ctrl + U⌘ + Option + U将当前网页保存为书签Ctrl + D⌘ + D将所有打开的标签页以书签的形式保存在新文件夹中Ctrl + Shift + D⌘ + Shift + D开启或关闭全屏模式F11⌘ + Ctrl + F向下滚动网页,一次一个屏幕空格键或 PgDn空格键向上滚动网页,一次一个屏幕Shift + 空格键或 PgUpShift + 空格键转到网页顶部Ctrl + Home 转到网页底部Ctrl + End 在网页上水平滚动按住 Shift 键并滚动鼠标滚轮 将光标移到文本字段中的上一个字词起始处Ctrl + 向左箭头键Option + 向左箭头键将光标移到下一个字词起始处Ctrl + 向右箭头键Option + 向右箭头键删除文本字段中的上一个字词Ctrl + BackspaceOption + Delete鼠标快捷键鼠标快捷键MacWindows / Linux在当前标签页中打开链接(仅限鼠标)将链接拖到标签页中将链接拖到标签页中在新的后台标签页中打开链接按住 Ctrl 键的同时点击链接按住 ⌘ 键的同时点击链接打开链接,并跳转到该链接按住 Ctrl + Shift 键的同时点击链接按住 ⌘ + Shift 键的同时点击链接打开链接,并跳转到该链接(仅使用鼠标)将链接拖到标签栏的空白区域将链接拖到标签栏的空白区域在新窗口中打开链接按住 Shift 键的同时点击链接按住 Shift 键的同时点击链接在新窗口中打开标签页(仅使用鼠标)将标签页拖出标签栏将标签页拖出标签栏将标签页移至当前窗口(仅限鼠标)将标签页拖到现有窗口中将标签页拖到现有窗口中将标签页移回其原始位置拖动标签页的同时按 Esc拖动标签页的同时按 Esc将当前网页保存为书签将相应网址拖动到书签栏中将相应网址拖动到书签栏中在网页上水平滚动按住 Shift 键并滚动鼠标滚轮 下载链接目标按住 Alt 键的同时点击链接按住 Option 键的同时点击链接显示浏览记录右键点击左上角“后退”/“前进”箭头,或左键点击左上角“后退”/“前进”箭头不释放右键点击左上角“后退”/“前进”箭头,或左键点击左上角“后退”/“前进”箭头不释放在最大化模式和窗口模式间切换双击标签栏的空白区域 放大网页上的所有内容按住 Ctrl 键并向上滚动鼠标滚轮 缩小网页上的所有内容按住 Ctrl 键并向下滚动鼠标滚轮 其它整理不易,难得齐全。 ...

October 17, 2019 · 4 min · jiezi

那些在国内还能使用的谷歌产品

前几天是谷歌成立21周年纪念日 https://www.google.com/doodle... ,感谢谷歌给互联网带来的便利。之前写过百度那些你可能不知道的百度产品 和腾讯那些你可能不知道的腾讯产品 ,正好再来说说谷歌,谷歌的所有产品 https://about.google/intl/zh-... 在这里有介绍,谷歌最好的产品自然是搜索了,可惜国内用不了(想上谷歌在公众号回复 谷歌 获取使用方法),尽管谷歌退出中国多年,但还是有不少服务能在国内继续使用,这里做个整理。 Chrome 浏览器我平常用的浏览器就是 Chrome 了,国内Chrome使用的是 google.cn域名(可惜不能用于搜索) https://www.google.cn/intl/zh... ,直接下载就好,强烈推荐你使用Chrome浏览器。 谷歌地图之前有域名 ditu.google.cn ,但现在上不去了 ,它会跳转到google.cn ,https://www.google.cn/maps 也会重定向到 google.cn ,但是电脑访问 http://www.google.cn//maps 居然还可以继续使用。 还有个更酷炫的谷歌地球https://earth.google.com/web/ ,可惜国内没法用。 谷歌翻译http://translate.google.cn/ 这个二级域名可以直接使用谷歌翻译。 谷歌开发者https://developers.google.cn/ 这是针对开发者使用的产品。https://developer.android.goo...安卓开发者应该很需要 https://developer.android.goo... golanggolang 是谷歌开发的一种语言,https://golang.google.cn/ 。文档也能打开https://golang.google.cn/doc/ ,当然使用go get 的时候推荐使用代理 https://goproxy.io/ https://goproxy.cn/ 谷歌广告https://ads.google.cn/intl/zh... 你应该经常能在网站上看到谷歌的广告,国内的公司也可以投放。 谷歌文档http://www.google.cn/docs/about/ 这个能打开,可惜点击后还是跳转到https://docs.google.com/docum... ,对应的国内可以使用腾讯文档。 谷歌 DNSGoogle Public DNS 是Google于2009年12月5日起提供的一个免费域名解析服务,具体看维基百科https://zh.wikipedia.org/wiki/Google_Public_DNS ping 8.8.8.8正在 Ping 8.8.8.8 具有 32 字节的数据:来自 8.8.8.8 的回复: 字节=32 时间=41ms TTL=52来自 8.8.8.8 的回复: 字节=32 时间=40ms TTL=52来自 8.8.8.8 的回复: 字节=32 时间=42ms TTL=52来自 8.8.8.8 的回复: 字节=32 时间=40ms TTL=528.8.8.8 的 Ping 统计信息: 数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),往返行程的估计时间(以毫秒为单位): 最短 = 40ms,最长 = 42ms,平均 = 40ms nslookup baidu.com 8.8.8.8服务器: dns.googleAddress: 8.8.8.8非权威应答:名称: baidu.comAddress: 39.156.69.79访问39.156.69.79 这个ip就可以直接访问百度。 ...

October 16, 2019 · 1 min · jiezi

译一文洞察-Chrome-DevTools-近半年更新了哪些新功能

本文首发于政采云前端团队博客:一文洞察 Chrome DevTools 近半年更新了哪些新功能本文由政采云前端团队 @子洋 同学翻译,原文可访问:https://developers.google.com... 前言工欲善其事,必先利其器。Chrome Devtools 是前端开发工程师不可或缺的开发工具,最近半年 Chrome 更新了 6 个版本,其中的 5 个版本里 Chrome Devtools 也更新了一些新功能,我们对最近的一些更新做了翻译整理,下面我们一起来看看近半年有哪些值得关注的新功能。 DevTools(Chrome 74)的新增功能高亮显示所有受 CSS 属性影响的节点将鼠标悬停在会影响节点盒子模型的 CSS 属性上,如 padding 或 margin ,会高亮显示受到这个属性声明影响的所有节点。 Audits 面板中的 Lighthouse v4新增加的 Tap targets are not sized appropriately 可以检查移动设备上的交互式元素(如按钮和链接)是否设置了合适的尺寸和间隔。 例如:点击目标的大小是否易于点击,或者是否距离其他可点击目标过近,更多: Tap targets are not sized appropriately PWA 分类使用新的徽章计分系统。 Lighthouse 相关介绍可参考:Lighthouse 新增 WebSocket 二进制消息查看器查看 WebSocket 二进制消息的内容: 打开 Network 面板。可参考 Inspect Network Activity 了解 Network 分析的基础使用。 ...

October 15, 2019 · 4 min · jiezi

调试效果让页面上的元素显示红色框范围

效果: 第二种简单的方法:我们需要借助 Chrome 的书签功能。 打开书签管理页右上角三个点「添加新书签」名称随意,粘贴以下代码到网址中javascript: (function() { var elements = document.body.getElementsByTagName('*'); var items = []; for (var i = 0; i < elements.length; i++) { if (elements[i].innerHTML.indexOf('html * { outline: 1px solid red }') != -1) { items.push(elements[i]); } } if (items.length > 0) { for (var i = 0; i < items.length; i++) { items[i].innerHTML = ''; } } else { document.body.innerHTML += '<style>html * { outline: 1px solid red }</style>'; }})();然后我们就可以在任意网站上点击刚才创建的书签,内部会判断是否存在调试的 style。存在的话就删除,不存在的话就添加,通过这种方式我们就能很方便的通过这个技巧查看任意网页的布局了。 ...

October 15, 2019 · 1 min · jiezi

Pinbox跨平台书签管理工具

日常上网,总会遇到需要收藏的网站,一般我们会用浏览器自带的书签工具来收藏,但是当书签量过多的时候就不容易管理,并且各个浏览器之间也不能互通,而Pinbox很好的解决了这些问题。 Pinbox 主打功能是收藏和收藏管理,但是围绕着收藏又做了很多特别方便的辅助功能,比如可以给某个收藏添加快捷键,可以编辑收藏的标题和描述,还有会抓取网页的缩略图。 Pinbox 不仅仅可以收藏网页,还可以收藏图片和文字。 一个网站怎么能吸引用户,第一个关键就是要界面好看,Pinbox 的界面可以说是非常有品质的,干净简约但又不失单调,整个网页给人一种轻盈素雅的感觉。 收藏使用三种方式展示 卡片模式 列表模式 和 极简模式 收藏可以通过拖拽卡片的方式轻松的移动到左侧任何收藏集里或者回收站里 也可以通过多选批量操作,支持按住 Shift 键快速选中卡片 文本收藏支持 Markdown格式,代码可以高亮显示,很适合收藏代码片段 点击右上角的加号可以添加网页或文字或者图片地址,也可以导入本地书签 最近 Pinbox 上线了主题色和暗黑模式,可以自由的选择自己喜欢的颜色作为主题色 提供了6 种主题颜色可以任意选择,支持暗黑模式和跟随系统功能 跟随系统在这里说一下,如果用的是Chrome系浏览器,选择了跟随系统,Pinbox 就会随着系统的模式而改变,也就是说当系统设置为夜晚模式,Pinbox 会自动跟随为暗黑模式,系统设置为白天,Pinbox 会自动设置为亮色,很好的提高了用户体验。 暗黑模式下的 Pinbox 现在 Pinbox 还很小众,用的人也不多,但是它出色的设计和完美的功能可以说是一款品质很高的产品了,能看出它背后团队的认真和用心,是真的想要做好产品,希望 Pinbox 能越做越好,保持初心,加油!

October 15, 2019 · 1 min · jiezi

python中的常见作图

本篇博文主要介绍一下python中常见的作图方式 线形图import matplotlib.pyplot as pltimport numpy as np#生成数据x = np.arange(0, 10, 0.2)y = np.sin(x)# 生成图形plt.plot(x, y)plt.show() 或者是类似matlab的代码风格,两者结果类似。 # Matlab 风格from pylab import *x = arange(0, 10, 0.2)y = sin(x)plot(x, y)show()在一个图形中画多张子图,类似于matlab中的subplot函数。 import matplotlib.pyplot as pltimport numpy as npx = np.arange(0, 10, 0.2)y = np.sin(x)z = np.cos(x)# 在第一个坐标轴上,画上正弦信号fig, axs = plt.subplots(nrows=2, ncols=1)axs[0].plot(x, y)axs[0].set_ylabel('Sine')# 第二个坐标轴axs[1].plot(x, z)axs[1].set_ylabel('Cosine')plt.show() 散点图# 单变量数据import numpy as npimport matplotlib.pyplot as pltimport pandas as pdimport scipy.stats as statsimport seaborn as sns# 生成数据x = np.random.randn(500)# 绘制图形plt.plot(x, '.')plt.show()# 展示 ...

October 14, 2019 · 1 min · jiezi

H5唤醒App快速直达App核心页面

在这个流量为王的互联网背景下,移动端的H5页面显然在导流上承担着重要作用,在H5页面上,我们对引流的需求有两种: 一是引导已下载用户从H5页面唤醒App并直达指定场景二是引导未下载用户从H5页面下载App,首次打开App时直达指定场景从运营角度来看,引导已下载用户打开App,能提高用户粘性和活跃度,而用户在App内的产品体验自然也比H5页面要好;引导未下载用户下载App并进入指定页面,显然能给用户更好的产品初体验。 这里其实就解释了我们做H5唤醒App并直达指定页面的必要性。 涉及哪些要素?唤醒App这件事,在不同平台要采用不同的方法,主要是这三个: URL SchemeUniversal LinkAndroid App Links1、URL Scheme URL Scheme是iOS、Android都兼容的机制,只需要原生App开发时注册Scheme即可,用户点击此类链接时,会自动唤醒App,并借助URL Router机制跳转到指定页面。 <scheme name> : <hierarchical part> [ ? <query> ] [ # <fragment> ]<scheme name>:是scheme的名称,代表着协议名称。<hierarchical part>:它包含 authority 和 path。<query>:可选项目,隔开或&隔开的键值对<key>=<value><fragmentg> :可选项目包,其它额外的标识信息 尽管URL Scheme兼容性高,但却存在许多限制,比如: 国内各个厂商浏览器差异很大,当要被唤醒的目标App未安装时,这个链接很容易出错。当注册有多个Scheme相同的时候,目前是没有办法区分的。不支持从其他App中的UIWebView中跳转到目标App。被部分主流平台禁止,微信、微博、QQ浏览器、手机百度中都已经被禁止使用。正是由于这些限制的存在,苹果和安卓都不约而同发布了自己的第二套方案:iOS的Universal Link、Android的App Links。 2、Universal Link Universal Link是iOS9后苹果推出的通用链接技术,能够方便的通过一个https链接来打开App指定页面,不需要额外的判断,如果没有安装App,可以跳转到自定义地址。 相对Scheme的优势在于,Universal Link是一个Web Link,因此少了很多麻烦: 当用户已安装该App时,不需要加载任何页面,能够立即唤醒App,用户未安装App,则跳去对应的web link(自定义页面)。Universal Links支持从其他App中的UIWebView中跳转到目标app。提供Universal Link给别的App进行App间的交流,然而对方并不能够用这个方法去检测你的App是否被安装,具有比较好的隐私性。绝大多数平台都支持Universal Link,微信7.0.5版本也解除了对Universal Link的限制,同时也能被搜索引擎索引。 3、App Links Android M以上版本可以通过App Links,让用户在点击一个链接时跳转到App的指定页面,前提是这个App已经安装并经过验证。App Links的最大的作用,就是可以避免从页面唤醒App时出现的选择浏览器选项框,前提是必须注册相应的Scheme,就可以实现直接打开关联的App。 实际上App Links和Universal Links差异不大,但相对来说有不同的限制: App links在国内的支持还不够,部分安卓浏览器并不支持跳转至App,而是直接在浏览器上打开对应页面。系统询问是否打开对应App时,假如用户选择“取消”并且选中了“记住此操作”,那么用户以后就无法再跳转App。几个方案的缺陷这几种方式无论哪种都无法解决这几个问题: 当用户未安装目标App时,无法保留用户停留的上下文,也就是说,用户下载完App后,无法在首次打开App时还原指定页面。Web目前无法监听App是否已安装,因此这几个方案都需要一些其他方法兼容唤醒App,或者跳转下载页面。那么怎样实现用户安装App后进入指定页面呢? 众所周知,苹果出于用户隐私的保护,设置了名为沙盒的机制:应用只能访问它声明可以访问的资源,但沙盒也阻碍了应用间合理的信息共享。 但也不是完全没办法,比如使用模糊匹配,尽可能收集设备的特征,将Web和App上的信息点配合算法做一个匹配是可以做到的,但准确率和成功率就取决于算法本身。如果App本身业务需求不高,那么低精度的方案也可以满足,但如果业务上需要一个能做到一对一精准匹配的方案,那么精准度不够高显然会影响业务的开展。 第三方服务如果嫌精准度不够高或者实现难度太大的话,可以交给专业的第三方去做,毕竟这几项技术是基于系统平台的,Android 及 iOS 每个系统版本的迭代后,配置方式都会有新的变化,且安卓机型众多,浏览器众多等也会导致出现兼容问题,开发者自行研发的话,资源配置以及系统更新后的维护成本是比较高的,还要考虑各种各样的跳转场景问题。 ...

October 9, 2019 · 1 min · jiezi

Postman登陆权限给postman的请求添加cookie以及使用interceptor拦截浏览器发送的请求

要使用postman测试开发的接口时,遇到了登陆权限的问题,本项目的权限是根据cookie中的某个值来做的判断,那么就需要在发送post请求的时候附带cookie内容通过interceptor拦截请求拦截器的好处是,不需要手动填写所有参数,而是直接截取到某个http请求的左右参数设置点击该按钮,弹出拦截器相关设置窗口点击 interceptor 按钮点击 ON 打开拦截器,此时右侧的应该出现 CONNECTED 的绿色小点,如果是 UNCONNECTED 的灰色小点,可以参考文档设置在哪里保存拦截的请求对拦截的请求做筛选 设置不同的http请求公用的 cookie通过在chrome中查看线上的接口调用信息,发现登陆权限是通过cookie中的session来确定的,这样就可以把这条cookie在postman中设置出来,就可以在postman中测试post请求了。点击按钮,弹出cookie设置的窗口输入domin的名称保存domin添加具体的cookie参数,每一条都要在这里添加一下前面的cookie的name,后面的是value保存该domin下的这一条cookie 常见问题拦截器是 UNCONNECTED 的灰色小点官方提到了这样的解决方案官方提到了这样的解决方案 核心内容是: The cookies and domains will be populated automatically. Can you confirm the following: Chrome is open, and has the Interceptor extension installed (v0.2.26)谷歌浏览器是打开状态,且已经安装Interceptor扩展You’ve completed the installation steps for the bridge已经完成安装 bridgeThe Interceptor Status isn’t updating to ‘Interceptor Connected’ even after restarting Chrome重启谷歌浏览器后,Interceptor应用,处于 连接中 的状态Interceptor 是一个用于拦截chorme浏览器的http请求的拦截器,可以把相关请求发送给postman软件。Interceptor Bridge 是用来建立浏览器和postman软件之间信息连接通道的一个小应用,需要手动安装。根据该方案,就可以使得 UNCONNECTED 的灰色小点变成 CONNECTED 的绿色小点

October 8, 2019 · 1 min · jiezi

打开chrome一次性打开了5个进程

打开chrome,一次性打开了5个进程?!先解释一下为什么会有这么多个进程,再说为什么需要创建这么多进程。那是因为现代浏览器采用的都是多进程浏览器,每个进程处理一个任务。 以chrome浏览器为例,打开一个chrome浏览器最少会产生4个进程,分别是: 1. 浏览器进程 2. 网络进程 3. GPU进程 4. 页面进程(正常情况下一个页面一个进程,特殊情况下面详细讲) 5. 插件进程(如果有插件的话,一个插件一个进程)详细如下图:(如何查看下图这种详细的进程,chrome右上角三个点 --> 更多工具 --> 任务管理器) 特殊情况下,两个页面会共用一个页面进程:chrome 默认每个页面一个进程,特殊情况:如果你从当前页面进入另一个新的页面,而且新页面的域名和当前页面一样,那么新页面会共用当前页面的页面进程,如下图:(场景:我从文章的评论者的名字进入了他的个人主页) 那么为什么chrome要创建这么多进程,以前的单进程架构不好吗?先说说之前的单进程架构存在的问题: 不流畅 插件:插件和页面使用同一个进程,插件会堵塞页面的加载。js: 其他页面js的死循环或者页面资源加载慢会导致整个浏览器的其他页面加载都卡死或变慢。不安全 插件:插件的权限过大,可以读取和修改本地文件,甚至修改电脑配置文件(使用c/c++编写的插件,可以完全控制你的电脑)。js: js可以通过浏览器的漏洞获取电脑权限,接浏览器之手修改本机配置。不稳定 插件:插件大部分是第三方编写的,水平参差不齐,崩溃也是家常便饭,插件的崩溃将直接导致浏览器无响应或崩溃。js: 一个页面js的死循环或崩溃将导致其他页面也卡死或崩溃。所以在多年的研究、开发后,多进程架构c位出道,基本解决了这些的问题: 流畅性: 插件和页面的js只能影响自己的进程,死循环或资源加载慢只能影响自己。(当然 现代浏览器特别吃cpu和内存资源,cpu内存吃满了还是会卡,多进程浏览器的缺点)安全性 安全沙箱:系统对进程使用沙箱机制,无法写数据,只能读有限的数据,通常是你当前域名下载的文件,将恶意插件和js的后门堵死了。稳定性: 因为进程间是相互隔离的,所以当一个页面或一个插件崩溃时,仅仅只会影响到当前页面和那个插件本身,完美解决一颗老鼠屎的问题。欢迎交流,有不完善的地方欢迎指出

September 9, 2019 · 1 min · jiezi

基于TensorFlow框架搭建一个最简单的CNN框架

项目简介本文将使用python,并借助TensorFlow框架搭建一个最简单的CNN框架,来实现对手写数字的识别。 本文搭建的CNN框架结构【1】输入层(本文的输入是一个28*28且为单通道的图片,所以输入层有784个节点)【2】第一个卷积层(该卷积层包含了32个不同的55的卷积核,即该卷积层提取了32种不同图形特征,【5,5,1,32】表示卷积核尺寸为55,1个颜色通道,32个不同的卷积核)【3】第一个卷积层后的最大池化层【4】第二个卷积层(该卷积层包含了64个不同的55的卷积核,即该卷积层提取了32种不同图形特征,【5,5,32,64】表示卷积核尺寸为55,64个不同的卷积核)【5】第二个卷积层后的最大池化层【6】全连接层【7】一个Dropout层(为了减轻过拟合,在训练时,我们随机丢弃一部分节点的数据来减轻过拟合,预测是则保留全部数据来追求最好的预测性能)【8】Softmax层,得到最后的概率输出。【9】定义损失函数为交叉熵(cross entropy),优化器使用Adam【10】得到模型的预测精度 项目代码导入相应的库from tensorflow.examples.tutorials.mnist import input_dataimport tensorflow as tf 导入手写数字数据集mnist = input_data.read_data_sets("MNIST_data/",one_hot = True)sess = tf.InteractiveSession() 定义生成权重的函数def weight_variabel(shape): initial = tf.truncated_normal(shape,stddev = 0.1)return tf.Variable(initial)定义生成偏重的函数def bias_variable(shape): initial = tf.constant(0.1,shape = shape)return tf.Variable(initial)定义生成卷积层的函数卷积层def conv2d(x,W): return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding='SAME')池化层定义生成最大池化层函数def max_pool_2x2(x): return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1], padding='SAME')传入输入的变量x = tf.placeholder(tf.float32,[None,784]) 传入标签的变量y_ = tf.placeholder(tf.float32,[None,10]) 将1D的图片转为28*28的2D照片x_image = tf.reshape(x,[-1,28,28,1]) 我们定义第一个卷积层权重W_conv1 = weight_variabel([5,5,1,32]) 偏置b_conv1 = bias_variable([32]) 卷积核h_conv1 = tf.nn.relu(conv2d(x_image,W_conv1)+b_conv1) 最大池化层h_pool1 = max_pool_2x2(h_conv1) 定义第二个卷积层权重W_conv2 = weight_variabel([5,5,32,64]) 偏置b_conv2 = bias_variable([64]) 卷积核h_conv2 = tf.nn.relu(conv2d(h_pool1,W_conv2)+b_conv2) ...

September 9, 2019 · 1 min · jiezi

解析移动端滚动穿透

滚动穿透在移动端开发中是一个很常见的问题,产生诡异的交互行为,影响用户体验,同时也让我们的产品看起来不那么“专业”。虽然不少产品选择容忍了这样的行为,但是作为追求极致的工程师,应该去了解为什么会产生以及如何去解决。 什么是滚动穿透移动端开发中避免不了会在页面上进行弹窗、加浮层等这种操作。一个最常见的场景就是整个页面上有一个遮罩层,上面画着各种各样的东西,具体是什么就不讨论。实现这样一个遮罩层可难不住即使是一个刚开始写前端的小白。但是这里有一个问题就是如果不对遮罩层做任何处理,当用户在上面滑动时会发现遮罩层下方的页面居然也在滚动,这就很 interesting 了。就如下面的例子,一个名为mask长宽都是屏幕大小的遮罩层,我们在上面滑动时,下面的内容也在跟随滚动,即滚动“穿透”到了下方,这就是滚动穿透(scroll-chaining)。 上方 demo 的遮罩层底部是一个逐渐变蓝的内容容器,但是滑动上面遮罩层时,底部也跟随滚动了,这只是一个最简单的场景,后面我们会讨论更复杂的情况。 为什么会出现目前 Google 上搜滚动穿透会出现一大堆教你如何解决的文章,但是它们都是在告诉你怎么解决怎么 hack 掉这种交互异常。并没有告诉读者为什么会产生这种行为,甚至认为这是浏览器的一个 bug。对于我来说这个是难以理解的,因为就算解决了问题,其实也并不知道问题的根本是怎样的。 认知误区有一个误区就是我们设置了一个和屏幕一样大小的遮罩层,盖住了下面的内容,按理说我们应该能屏蔽掉下方的所有事件也就是说不可能触发下面内容的滚动。那么我们就去看一下规范,什么时候会触发滚动。 // https://www.w3.org/TR/2016/WD...When asked to run the scroll steps for a Document doc, run these steps: For each item target in doc’s pending scroll event targets, in the order they were added to the list, run these substeps:If target is a Document, fire an event named scroll that bubbles at target.Otherwise, fire an event named scroll at target.Empty doc’s pending scroll event targets.通过规范我们可以明白的 2 点是,首先滚动的 target 可以是 document 和里面的 element。其次,在 element 上的 scroll 事件是不冒泡的,document 上的 scroll 事件冒泡。 ...

September 7, 2019 · 2 min · jiezi

Google-Chrome浏览器插件和油猴脚本推荐

前言到了新加坡再也不用考虑科学上网的问题,加上macOS跨平台浏览器做得比较成熟的自然是Google Chrome和Firefox,在Windows平台用了十几年的Maxthon,期间也尝试过无数第三方浏览器,傲游浏览器努力改变着世界却也渐行渐远,有着同样命运的应该还包括我从M8用到MX2的魅族吧。回到Google Chrome浏览器插件和油猴脚本推荐正题,Google Chrome除了最重要的快以外,更重要的是Chrome Web Store上一系列好用插件,我很喜欢Chrome简单纯粹的设计和极致的性能。在插件的推荐上分为通用和开发者两部分来写方便区分,大部分Chrome可用的插件Firefox也同样适用,如果有遗漏或有更好用的同类型插件和脚本欢迎留言分享。 Google Chrome浏览器插件和油猴脚本推荐更新历史2019年08月20日 - 添加自用部分插件和脚本2019年08月01日 - 初稿 阅读原文 - https://wsgzao.github.io/post... 扩展阅读 The 100 Best Free Google Chrome Extensions Chrome Firefox 双修,2019 年度最喜欢浏览器拓展 脚本里的 “赤兔”,2019 年度最喜欢油猴脚本 Chrome插件推荐以下链接大部分都是Google Chrome Webstore,如果无法访问可以考虑从第三方下载到本地导入Chrome Web Store Crx4Chrome Chrome Extension Downloader 通用SimpleExtManager - 我个人首推的管理插件小工具,对于插件控们一定灰常有帮助 IE Tab - 为了向下兼容那些没有与时俱进的网站,大多数时候我们只能选择妥协 Undo Closed Tabs Button - Google原生取消了恢复网页的按钮的设计,你可以通过快捷键或者历史记录恢复,但这个小工具确实可以帮到我 Tampermonkey - 老牌的油猴管理工具,和Violentmonkey暴力猴相比哪款用得顺手选择哪个 沙拉查词-聚合词典划词翻译 - 我个人觉得这是目前Chrome划词翻译插件中体验最好的 Grammarly for Chrome - 智能检查英文语法拼写错误,在Web写邮件和文档时会发现它的重要价值 Evernote Web Clipper - 中文称为印象笔记,平时会把优质的内容保存到Evernote中,虽然没有OneNote功能强大但胜在简单方便可跨平台同步 ...

August 20, 2019 · 1 min · jiezi

JavaScript深入浅出第5课Chrome是如何成功的

摘要: Chrome改变世界。 《JavaScript深入浅出》系列: JavaScript深入浅出第1课:箭头函数中的this究竟是什么鬼?JavaScript深入浅出第2课:函数是一等公民是什么意思呢?JavaScript深入浅出第3课:什么是垃圾回收算法?JavaScript深入浅出第4课:V8引擎是如何工作的?JavaScript深入浅出第5课:Chrome是如何成功的?前言在上一篇博客中,我聊了一下JavaScript引擎V8的工作原理,顺其自然,接下来应该来聊聊渲染引擎Blink或者Chrome浏览器的工作原理。但是,这2个坑以后再填。 这次我重点聊聊产品,当然免不了涉及一些技术。 几乎所有JavaScript开发者每天都在使用Chrome,大家知道它是如何成为浏览器霸主的吗? Google为什么要做浏览器?其实,Google的联合创始人Larry Page和Sergey Brin早在2001年就想做浏览器,但是当时的CEO施密特一直反对,因为从头开发一个浏览器的成本太高了,不是一个创业公司可以承受的。因此,Google直到2006年,公司已经上市2年了,才开始做浏览器,秘密开发了2年,Chrome才正式发布。 Google真正开始开发Chrome是2006年,当时IE的市场占有率高达80%,Firefox大概是10%。自从击败Netscape之后,IE似乎可以高枕无忧了。如果那时候有人要做一个浏览器,大多数人都会质疑,还需要多个浏览器干嘛?IE和Firefox又不是不能用。 但是,2006年时的Web早已经不再是简单的静态页面,Gmail、Youtube、Google Maps,Facebook这些复杂的Web应用已经出现一段时间了,传统浏览器在架构、性能以及稳定性上已经逐渐不再适用了,这时正是需要一款更加强大的浏览器来满足用户与Web开发者的需求。 Google所做的最重要的事情,就是对成千上万的网页进行排序,所以它存在的意义是基于网页的。而一个更快、更好的浏览器,可以促进Web技术的发展,网页会越来越多,越来越好,用户花在Web上的时间越来越多,这对Google是有益。因此,Google要做浏览器,不只是想要一个搜索入口那么简单。 Google希望通过Chrome浏览器来促进Web技术的发展,从而让自己受益,这也不是什么秘密,Chrome团队的人都是这么说的,Google现在的CEO是Sundar Pichai,他当年发布Chrome的时候是这样说的: We hope to collaborate with the entire community to help drive the web forward.这样假大空的话当年大概没几个人相信,但是这不重要,重要的是Google真的做到了,Chrome确实推动了Web技术的发展。没有Chrome的话,现在的Web技术大概确实得落后不少。 如果Google只是想要一个搜索入口,它可以收购一个浏览器,或者基于开源浏览器套一个壳,做一下账户系统就够了,再通过Google网站进行推广。国内各个大厂的浏览器都是基于Chrome的开源版本Chromium实现的,某个浏览器甚至直接打包了Chrome的安装包。 既然Google想做的事情是推动Web技术发展,如果沿用旧的思想和技术的话,显然是做不到的。于是,他们设计了一个多进程的浏览器架构,重新写了一个性能彪悍的JavaScript引擎V8,后来又基于Webkit做了一个新的渲染引擎Blink。 不妨这样说,Google与国内的搜索引擎巨头们的还差一个Chrome浏览器。后者看到的是搜索流量带来的商业价值以及重新开发一个浏览器的巨大成本,而前者看到了Web技术发展对搜索引擎本身的长远价值。 Chrome就一定能成功吗?Google终于决定做浏览器了,但这事能不能做成,其实也不一定。和每一个大公司一样,Google失败的项目远远多于成功的项目,大家不妨看看Killed by Google里面的列表。 Google确实有很多非常成功的产品,比如Android,Youtube,Google Maps, DeepMind,但是它们其实都是收购来的。Chrome算是Google为数不多的真正从零开始打造出来的产品。 下面这张图是Chrome发布时的照片: 图片来源:Niall Kennedy 照片中从左至右是Larry Page, Brian Rakowski, Sundar Pichai, Sergey Brin, Darin Fisher, Lars Bak和Ben Goodger,他们都是Chrome浏览器最关键人物,也都因为Chrome的成功而收益不菲。 Larry Page和Sergey Brin是Google的创始人,他们一直希望做浏览器;Sundar Pichai当时是Google负责产品的副总裁,Chrome也在他的管理范围之类,现在他是Google的CEO;Brian Rakowski当时是Chrome的产品经理,现在是Google负责产品的副总裁;Lars Bak是JavaScript引擎V8的负责人,曾长期从事编程语言的虚拟机开发工作;Darin Fisher是Chrome最早期的开发者,之前是Firefox的工程师,现在是Google负责Chrome的副总裁;Ben Goodger是Chrome最早期的开发者,之前是Firefox的工程师,现在的职级为Distinguished Engineer,仅次于Google Fellow以及Senior Google Fellow;照片中大家都挺开心的,秘密开发了2年的Chrome终于发布了,但是他们能想到10年后Chrome可以占有接近70%的市场份额吗? ...

August 8, 2019 · 2 min · jiezi

神奇的标签块级元素行内元素空元素

最近有人问我,前端模块为什么是空着的。是呀,前端模块一直没有着手开始写,不是因为没有东西可写,是一直在想着以什么样的前端开篇,有太多东西要写,但如果没有规划的写,可能久而久之的就遗弃了。所以再三决定,从我第一次认识前端知识开始写起,当然对于那些前端大牛,也许这篇文章没有营养,但我相信也不乏一些刚起步进入前端行业的新人,所以大家选择性预览。 前端是一个很容易入门,但却很难走进去的一个行业。看似简单,但一旦深入,就“不可自拔”。说到,前端,肯定少不了要认识他的组成元素,那这就涉及到块级元素,行内元素以及一些空元素。 Html标签html标签定义:是由一对尖括号包裹的单词构成,例如: <html>.标签不区分大小写<html> 和 <HTML>, 推荐使用小写.标签分为两部分: 开始标签<html> 和 结束标签</html>, 两个标签之间的部分我们叫做标签体.有些标签功能比较简单,使用一个标签即可,这种标签叫做自闭和标签,例如: <br/><hr/><input/><img/>标签可以嵌套,例如:<a><b><b/><a/>;但是不能交叉嵌套,例如:<a><b><a/><b/>块级元素总是在新行上开始;高度,行高以及外边距和内边距都可控制;宽度缺省是它的容器的100%,除非设定一个宽度。它可以容纳内联元素和其他块元素 块级元素分类(双标签,eg:<div></div>):<h1>,<h2>,<h3>,<h4>,<h5>,<h6> 定义 HTML 标题。<div> 定义文档中的节。<p> 定义段落。<ul> 定义无序列表。<ol> 定义有序列表。<li> 定义列表的项目。<dl> 自定义定义列表。<dt> 自定义定义列表中的项目。<dd> 自定义定义列表中项目的描述。<table> 定义表格。<thead> 定义表格中的表头内容。<tbody> 定义表格中的主体内容。<tfoot> 定义表格中的表注内容(脚注)。<th> 定义表格中的表头单元格。<tr> 定义表格中的行。<td> 定义表格中的单元。<pre> 定义预格式文本。<address> 定义地址。<article> 定义文章。<aside> 定义页面内容之外的内容。<audio> 定义声音内容。<video> 定义视频。<blockquote> 定义长的引用。<canvas> 定义图形。<caption> 定义表格标题。<details> 定义元素的细节。<fieldset> 定义围绕表单中元素的边框。<figcaption> 定义 figure 元素的标题。<figure> 定义媒介内容的分组,以及它们的标题。<footer> 定义 section 或 page 的页脚。<form> 定义供用户输入的 HTML 表单。<header> 定义 section 或 page 的页眉。<nav> 定义导航链接。<noframes> 定义针对不支持框架的用户的替代内容。<noscript> 定义针对不支持客户端脚本的用户的替代内容。<legend> 定义 fieldset 元素的标题。<menu> 定义命令的列表或菜单。<meter> 定义预定义范围内的度量。<output> 定义输出的一些类型。<section> 定义 section。行内元素和其他元素都在一行上;高,行高及外边距和内边距不可改变;宽度就是它的文字或图片的宽度,不可改变;内联元素只能容纳文本或者其他内联元素; ...

August 7, 2019 · 1 min · jiezi

实用浏览器调试技巧动画节点删除节点增加

今天分享一些平时不常用,但总有一天你会用到的浏览器调试技巧。先来看一个H5页面,下面是地址http://liticool.info/wsvist/i... (订阅号里无法跳转外部链接的话请复制此链接在微信中打开liticool.info/wsvist/index.html#/?sharekey=0a4384df4f65b6b47a74f76f8f3f3e1d&source=wxd56b51346bc8cbfc)我是在微信中看到这个H5场景的,看到了里面酷炫的动画。就想看看这个效果是怎么实现的,然后我把地址复制到了浏览器中,我的踩坑之路也就此开始了。 坑1:当我把链接复制到浏览器之后,发现在浏览器中一直显示一个loading。不能正常观看。 思考:为啥在微信中可以,在浏览中就不行呢?然后立马想到了用微信开发者工具打开,果然好使。可以看到酷炫的动画了。然后我F12打开调试工具,选取其中一个dom元素。准备看它的css代码。但是问题又来了。 坑2:dom元素一直在动,css代码也一直在变。 经过高人指点:点击关闭按钮旁边的三个点->Moretools->Animation.你会发现出现一个新的面板,点击那个暂停按钮。你会发现css动画停止了。如图。坑3:dom动一会儿就被删除了。出现了新的场景(渲染了新的dom元素)这该如何是好. 动画虽然停止了,但是dom的删除是js控制的。js的还在运行。过几秒之后又页面又重新渲染了其他dom元素。怎么让js也停止执行呢,首先想到的是打个断点,但问题是去哪里打断点呢。打的早了dom还没渲染出来,打的地方不对代码可能不走那里。于是高人又出来指点了:可以在dom节点上打断点:选取一个dom元素,右键->Break On->node removal.这样在此dom节点被删除的时候,程序就会停下来。如图。如此这般,我们就可以轻松找到想要看的css代码了。补充:还有一种阻止js执行的办法,就是禁用javascript。还是点击三个点->Settings->Debugger->Disable JavaScript打勾就可以了。这样js就不会执行了,dom元素也不会被删掉了。如图:彩蛋:介绍一个在浏览器中全局搜索代码的方法,点击Sources面板,会看到左侧有目录结构,右键目录结构->Search in all files。这样就可以在所有文件中搜索代码了。这个在开发中还是很有作用的。如图:小扩展:还有一个场景:一个页面会从后台请求字体包,字体包会在某个时刻通过js加入到style标签中。但是我们不知道是哪段js代码执行了这个操作。现在想找到这个代码,应该怎么办呢?方法:给style标签打断点:右键style标签->Break On->subtree modifications 这样,在style中插入@font-face时,就会直接停在执行插入的那一段js代码处。如图 作者:易企秀——Hison

July 16, 2019 · 1 min · jiezi

Chrome浏览器一下载就崩溃的解决方法

Chrome浏览器一下载就崩溃的解决方法环境操作系统:win10浏览器:chrome输入法: 酷狗问题描述:一下载chrome就崩溃 解决办法先切换输入法,可以换成win10自带数据法,然后点击下载 结果:正常下载

July 15, 2019 · 1 min · jiezi

深入前端彻底搞懂JS的运行机制

最近看了很多关于JS运行机制的文章,每篇都获益匪浅,但各有不同,所以在这里对这几篇文章里说的很精辟的地方做一个总结,参考文章链接见最后。本文博客地址了解进程和线程进程是应用程序的执行实例,每一个进程都是由私有的虚拟地址空间、代码、数据和其它系统资源所组成;进程在运行过程中能够申请创建和使用系统资源(如- 独立的内存区域等),这些资源也会随着进程的终止而被销毁。而线程则是进程内的一个独立执行单元,在不同的线程之间是可以共享进程资源的,所以在多线程的情况下,需要特别注意对临界资源的访问控制。在系统创建进程之后就开始启动执行进程的主线程,而进程的生命周期和这个主线程的生命周期一致,主线程的退出也就意味着进程的终止和销毁。主线程是由系统进程所创建的,同时用户也可以自主创建其它线程,这一系列的线程都会并发地运行于同一个进程中。浏览器是多进程的详情看我上篇总结浏览器执行机制的文章-深入前端-彻底搞懂浏览器运行机制浏览器每打开一个标签页,就相当于创建了一个独立的浏览器进程。Browser进程:浏览器的主进程(负责协调、主控),只有一个。作用有第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建GPU进程:最多一个,用于3D绘制等浏览器渲染进程(浏览器内核)javascript是一门单线程语言jS运行在浏览器中,是单线程的,但每个tab标签页都是一个进程,都含有不同JS线程分别执行,,一个Tab页(renderer进程)中无论什么时候都只有一个JS线程在运行JS程序既然是单线程的,在某个特定的时刻只有特定的代码能够被执行,并阻塞其它的代码。而浏览器是事件驱动的(Event driven),浏览器中很多行为是异步(Asynchronized)的,会创建事件并放入执行队列中。javascript引擎是单线程处理它的任务队列,你可以理解成就是普通函数和回调函数构成的队列。当异步事件发生时,如(鼠标点击事件发生、定时器触发事件发生、XMLHttpRequest完成回调触发等),将他们放入执行队列,等待当前代码执行完成。javascript引擎是基于事件驱动单线程执行的,JS引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个JS线程在运行JS程序。所以一切javascript版的"多线程"都是用单线程模拟出来的为什么JavaScript是单线程?与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?任务队列"任务队列"是一个事件的队列(也可以理解成消息的队列),IO设备完成一项任务,就在"任务队列"中添加一个事件,表示相关的异步任务可以进入"执行栈"了。主线程读取"任务队列",就是读取里面有哪些事件。"任务队列"中的事件,除了IO设备的事件以外,还包括一些用户产生的事件(比如鼠标点击、页面滚动等等),ajax请求等。只要指定过回调函数,这些事件发生时就会进入"任务队列",等待主线程读取。所谓"回调函数"(callback),就是那些会被主线程挂起来的代码。异步任务必须指定回调函数,当主线程开始执行异步任务,就是执行对应的回调函数。"任务队列"是一个先进先出的数据结构,排在前面的事件,优先被主线程读取。主线程的读取过程基本上是自动的,只要执行栈一清空,"任务队列"上第一位的事件就自动进入主线程。但是,由于存在后文提到的"定时器"功能,主线程首先要检查一下执行时间,某些事件只有到了规定的时间,才能返回主线程。同步和异步任务既然js是单线程,那么问题来了,某一些非常耗时间的任务就会导致阻塞,难道必须等前面的任务一步一步执行玩吗?比如我再排队就餐,前面很长的队列,我一直在那里等岂不是很傻逼,说以就会有排号系统产生,我们订餐后给我们一个号码,叫到号码直接去就行了,没交我们之前我们可以去干其他的事情。因此聪明的程序员将任务分为两类: 同步任务:同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务:异步任务指的是,不进入主线程、而进入"任务队列"(Event queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。 任务有更精细的定义:macro-task(宏任务):包括整体代码script(同步宏任务),setTimeout、setInterval(异步宏任务)micro-task(微任务):Promise,process.nextTick,ajax请求(异步微任务) macrotask(又称之为宏任务)可以理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)每一个task会从头到尾将这个任务执行完毕,不会执行其它浏览器为了能够使得JS内部task与DOM任务能够有序的执行,会在一个task执行结束后,在下一个 task 执行开始前,对页面进行重新渲染(task->渲染->task->...) microtask(又称为微任务),可以理解是在当前 task 执行结束后立即执行的任务也就是说,在当前task任务后,下一个task之前,在渲染之前所以它的响应速度相比setTimeout(setTimeout是task)会更快,因为无需等渲染也就是说,在某一个macrotask执行完后,就会将在它执行期间产生的所有microtask都执行完毕(在渲染前) 执行机制与事件循环主线程运行的时候,产生堆(heap)和栈(stack),栈中的代码调用各种外部API,它们在"任务队列"中加入各种事件(click,load,done)。只要栈中的代码执行完毕,主线程就会去读取"任务队列",依次执行那些事件所对应的回调函数。 那怎么知道主线程执行栈为执行完毕?js引擎存在monitoring process进程,会持续不断的检查主线程执行栈是否为空,一旦为空,就会去Event Queue那里检查是否有等待被调用的函数。 第一轮事件循环:主线程执行js整段代码(宏任务),将ajax、setTimeout、promise等回调函数注册到Event Queue,并区分宏任务和微任务。主线程提取并执行Event Queue 中的ajax、promise等所有微任务,并注册微任务中的异步任务到Event Queue。第二轮事件循环:主线程提取Event Queue 中的第一个宏任务(通常是setTimeout)。主线程执行setTimeout宏任务,并注册setTimeout代码中的异步任务到Event Queue(如果有)。执行Event Queue中的所有微任务,并注册微任务中的异步任务到Event Queue(如果有)。类似的循环:宏任务每执行完一个,就清空一次事件队列中的微任务。 注意:事件队列中分“宏任务队列”和“微任务队列”,每执行一次任务都可能注册新的宏任务或微任务到相应的任务队列中,只要遵循“每执行一个宏任务,就会清空一次事件队列中的所有微任务”这一循环规则,就不会弄乱。 说了那么多来点实例吧ajax普通异步请求实例let data = [];$.ajax({ url:www.javascript.com, data:data, success:() => { console.log('发送成功!'); }})console.log('代码执行结束');1.执行整个代码,遇到ajax异步操作 2.ajax进入Event Table,注册回调函数success。 3.执行console.log('代码执行结束')。 4.执行ajax异步操作 5.ajax事件完成,回调函数success进入Event Queue。 5.主线程从Event Queue读取回调函数success并执行。 普通微任务宏任务实例setTimeout(function(){ console.log('定时器开始啦')});new Promise(function(resolve){ console.log('马上执行for循环啦'); for(var i = 0; i < 10000; i++){ i == 99 && resolve(); }}).then(function(){ console.log('执行then函数啦')});console.log('代码执行结束');1.整段代码作为宏任务执行,遇到setTimeout宏任务分配到宏任务Event Queue中2.遇到promise内部为同步方法直接执行-“马上执行for循环啦”3.注册then回调到Eventqueen4.主代码宏任务执行完毕-“代码执行结束”5.主代码宏任务结束被monitoring process进程监听到,主任务执行Event Queue的微任务6.微任务执行完毕-“执行then函数啦”7.执行宏任务console.log('定时器开始啦') ...

July 15, 2019 · 1 min · jiezi

如何将Chrome本地安装的扩展应用导出到本地

有时由于种种原因,我们不能直接使用Chrome web store进行Chrome扩展应用的安装,这时可以让一位已经安装了某Chrome扩展应用的朋友将他的应用导出到本地成为.crx文件,然后发给你,这样你就可以通过.crx文件进行离线安装了。这种方式也可以用来作为Chrome扩展应用的备份。 我们先在线安装SAP UI5 inspector这个扩展应用: 根据ui5 inspector这个关键字进行搜索,在结果列表里选中,点击Add to Chrome: 安装完毕后,打开Chrome extension即扩展应用管理器的开发者模式,抄下UI5 inspector的ID: 通过这个ID,我们通过进入如下的路径,能发现安装好的UI5 inspector本地文件: C:Usersi042416AppDataLocalGoogleChromeUser DataDefaultExtensionsbebecogbafbighhaildooiibipcnbngo0.9.5_0 这时就可以把这些文件夹进行打包导出了,点击Pack extension: 输入路径C:Usersi042416AppDataLocalGoogleChromeUser DataDefaultExtensionsbebecogbafbighhaildooiibipcnbngo0.9.5_0,点击Pack Extension: 得到打包好的.crx文件。 发给你的朋友,他就可以进行离线安装了。 要获取更多Jerry的原创文章,请关注公众号"汪子熙":

July 14, 2019 · 1 min · jiezi

Chrome-浏览器扩展神器油猴

我平常工作最常用的浏览器就是 Chrome 了,Google 出品,值得信赖,用 Chrome 就不得不提浏览器扩展了,有了各种 Chrome 扩展,可以让你浏览器网页更方便,工作更高效。 Chrome 扩展可以在 Google 应用商店下载 https://chrome.google.com/webstore/category/extensions?hl=zh-CN 这里可以搜索安装你喜欢的各种扩展。 比如我装了很多扩展。 扩展这么多,其中的油猴 Tampermonkey 是必须推荐的一个,它是扩展中的王者,最强大的浏览器扩展。 安装油猴扩展油猴是个Chrome扩展,网站 https://www.tampermonkey.net/ 可以直接在官网下载 https://chrome.google.com/web... 直接安装即可。 如果上不了Google,可以在国内第三方Chrome 插件网站https://www.crx4chrome.com/ http://chromecj.com/ http://www.cnplugins.com/ https://www.chromefor.com/ 等搜索下载。下载的是个 crx 文件,然后打开 Chrome 扩展chrome://extensions/,打开开发者模式,将下载的crx文件拖进去,如果出错提示程序包无效。将 crx 后缀改为 zip 再拖进去就能安装成功了,浏览器右上角可以看到图标。 脚本网站有了油猴扩展,还需要配上脚本。安装完扩展后点击图标,选择 获取新脚本会进入网站https://www.tampermonkey.net/scripts.php 这里可以获取脚本来源,有3个来源网站http://userscripts-mirror.org/https://openuserjs.org/ https://greasyfork.org/ 这里推荐 greasyfork ,因为它支持中文。 打开网站首页https://greasyfork.org/zh-CN 可以看到很多脚本。 安装脚本也很简单,找到需要的脚本,进入页面,点击安装,然后管理面板即可看到已安装的脚本。 下面推荐些实用的脚本,开始打开新世界的大门。 搜索去广告功能介绍:去掉百度、搜狗、谷歌搜索结果的重定向,回归为网站的原始网址---附带有去除百度的广告 包括百度顶部和底部的垃圾广告,脚本地址https://greasyfork.org/zh-CN/scripts/14178 安装脚本前搜索 浏览器 前面3个是广告 安装脚本后的效果,广告没有了,你还可以自定义设置。 知乎网页助手功能介绍:1、知乎站外链接直接跳转至目标网址;2、自动展开问题全部信息,同时展示所有回答;3、去除知乎网页中的广告;4、知乎网页中短视频下载;5、解除知乎复制限制-划词复制(鼠标左键划词自动添加到剪切板) 脚本地址 https://greasyfork.org/zh-CN/scripts/384172 比如这个周杰伦的视频回答 https://www.zhihu.com/questio...安装脚本前安装后视频可以直接下载了。 微博浮图功能介绍:微博浮图控件,鼠标移过小图弹出浮动大图的脚本。脚本地址https://greasyfork.org/zh-CN/scripts/4233安装脚本前需要点击小图才能看到大图安装后效果,不用点击鼠标移上去即可看到大图,其实不限制微博,其他网站的图片一样可以。 百度网盘直链下载助手功能介绍:免客户端一键获取百度网盘文件真实下载地址,支持使用IDM,迅雷等下载工具下载。安装后会在对应界面出现【下载助手】按钮, 配合多线程下载工具达到提速的效果。脚本地址 https://greasyfork.org/zh-CN/scripts/39504 安装后不用安装网盘客户端就可以直接下载文件。 全网VIP视频免费破解功能介绍:懒人专用,全网VIP视频免费破解去广告、全网音乐直接下载、百度网盘直接下载、知乎视频下载等多合一版。脚本地址https://greasyfork.org/zh-CN/scripts/370634 ...

July 14, 2019 · 1 min · jiezi

清除-chrome-的-HSTS-307-缓存

如何解決? https://stackoverflow.com/que... chrome瀏覽器打開 chrome://net-internals/#hsts 先在 Query HSTS/PKP domain 查你被 307 Internal Redirect 的域名,如果是Not Found,這邊就不是你要的答案 如果有內容,如下圖 那就到 Delete domain security policies 輸入你被 307 Internal Redirect 的網址,然後Delete 他現在你能使用HTTP訪問該網址了

July 12, 2019 · 1 min · jiezi

快速理解TCPIP三次握手与四次挥手

TCP/IP三次握手TCP建立连接为什么是三次握手,而不是两次或四次?TCP,名为传输控制协议,是一种可靠的传输层协议,IP协议号为6。顺便说一句,原则上任何数据传输都无法确保绝对可靠,三次握手只是确保可靠的基本需要。 对应为客户端与服务器之间的通信:于是有了以下对话:我:1+1等于几?她:2,2+2等于几?我:4 首先两个人约定协议1.感觉网络情况不对的时候,任何一方都可以发起询问2.任何情况下,若发起询问后5秒还没收到回复,则认为网络不通3.网络不通的情况下等1min路由器之后再发起询问 对于我而言,发起 “1+1等于几”的询问后 若5s内没有收到回复,则认为网络不通若收到回复,则我确认①我能听到她的消息 ②她能听到我的消息,然后回复她的问题的答案对于她而言,当感觉网络情况不对的时候 若没有收到我的询问,则她发起询问若收到“1+1等于几”,则她确认 ①她可以听到我的消息,然后回复我的问题的答案和她的问题“2,2+2等于几”若5s内没有收到我的回复“4”,则她确认 ②我听不见她的消息若5s内收到了我的回复“4”,则她确认 ②我可以听见她的消息这样,如果上面的对话得以完成,就证明双方都可以确认自己可以听到对方的声音,对方也可以听到自己的声音! 这个解释足够简单了吧!接下来我们看四次挥手。 TCP/IP四次挥手三次握手耳熟能详,四次挥手估计就..所谓四次挥手(Four-Way Wavehand)即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中,这一过程由客户端或服务端任一方执行close来触发,整个流程如下图所示: 服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。简单点说,当被动方收到主动方的FIN报文通知时,它仅仅表示主动方没有数据再发送给被动方了。但未必被动方所有的数据都完整的发送给了主动方,所以被动方不会马上关闭SOCKET,它可能还需要发送一些数据给主动方后,再发送FIN报文给主动方,告诉主动方同意关闭连接,所以这里的ACK报文和FIN报文多数情况下都是分开发送的。

July 11, 2019 · 1 min · jiezi

JS事件冒泡与捕获

事件冒泡与事件捕获事件冒泡和事件捕获分别由微软和网景公司提出,这两个概念都是为了解决页面中事件流(事件发生顺序)的问题。 如下:假设三层div都有事件监听,这时我们点击的小的蓝方框,事件执行的顺序是怎么样的呢 <div id="s1" style="height: 400px;width: 400px;border: 1px solid red">红 <div id="s2" style="height: 200px;width: 200px;border: 1px solid yellow"> 黄 <div id="s3" style="height: 100px;width: 100px;border: 1px solid blue">蓝</div> </div></div> 事件冒泡微软提出了名为事件冒泡(event bubbling)的事件流。事件冒泡可以形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面。也就是说,事件会从最内层的元素开始发生,一直向上传播,直到document对象。因此在事件冒泡的概念下在div元素上发生click事件的顺序应该是div -> body -> html -> document 事件捕获网景提出另一种事件流名为事件捕获(event capturing)。与事件冒泡相反,事件会从最外层开始发生,直到最具体的元素。因此在事件捕获的概念下在div元素上发生click事件的顺序应该是document -> html -> body -> div -> div w3c 采用折中的方式,制定了统一的标准——先捕获再冒泡。addEventListener第三个参数默认值是false,表示在事件冒泡阶段调用事件处理函数;如果参数为true,则表示在事件捕获阶段调用处理函数。 测试事件冒泡-点击蓝色 s1 = document.getElementById('s1') s2 = document.getElementById('s2') s3 = document.getElementById('s3') s1.addEventListener("click",function(e){ console.log("红 冒泡事件");//从底层往上 },false);//第三个参数默认值是false,表示在事件冒泡阶段调用事件处理函数;如果参数为true,则表示在事件捕获阶段调用处理函数。 s2.addEventListener("click",function(e){ console.log("黄 冒泡事件"); },false); s3.addEventListener("click",function(e){ console.log("蓝 冒泡事件"); },false); 测试事件捕获-点击蓝色s1.addEventListener("click",function(e){ console.log("红 捕获事件"); },true); s2.addEventListener("click",function(e){ console.log("黄 捕获事件"); },true); s3.addEventListener("click",function(e){ console.log("蓝 捕获事件"); },true); ...

July 10, 2019 · 1 min · jiezi

使用Docker安装Gitlab及相关配置

最近在学习自动化部署的一些内容,自动化部署,涉及到的内容有Docker、Jenkins、Gitlab等内容,今天通过docker玩了一遍gitlab,下面是一些心得 安装GitlabDocker安装服务实在是太方便,我们通过docker来安装Gitlab,运行如下命令查看Gitlab的镜像文件 搜索镜像 sudo docker search gitlab看到镜像有很多,如果OFFICIAL这一项下面是[OK] 表示为官方的镜像,我这里使用第四个,因为这是中文版的,鄙人英语不好,还是看中文版的比较舒服。其实,中文版也就是安装了一个语言包而已,有兴趣可以自己安装第一个,然后再手动配置中文包 下载镜像 sudo docker pull twang2218/gitlab-ce-zh启动服务 docker run -d -p 8443:443 -p 8090:80 -p 8022:22 --restart always --name gitlab -v /usr/local/gitlab/etc:/etc/gitlab -v /usr/local/gitlab/log:/var/log/gitlab -v /usr/local/gitlab/data:/var/opt/gitlab --privileged=true twang2218/gitlab-ce-zh查看启动情况 // 添加-a 参数,把启动的,没有启动的都列出来sudo docker ps 配置Gitlab配置的时候,我们需要进入容器当中配置,如果直接修改我们映射到容器外部的配置文件,总会出现一些奇怪的问题,为了避免出现问题,尽量按照如下操作流程进行相关的配置和测试 第一步:进入容器 sudo docker exec -it gitlab bash第二步:修改gitlab.rb文件 sudo cd /etc/gitlabsudo vim gitlab.rb第三步:修改IP和端口 该部分内容的修改是为了解决,我们再gitlab创建项目的时候,项目访问地址是容器id的问题 // 可以使用/ 来查找关键字,找到指定的内容,然后通过n来下一个查找// 在gitlab创建项目时候http地址的host(不用添加端口)external_url 'http://xx.xx.xx.xx'// 在gitlab创建项目时候ssh地址的hostgitlab_rails['gitlab_ssh_host'] = 'xx.xx.xx.xx'(不用添加端口)# docker run 的时候我们把22端口映射为外部的8022了,这里修改下gitlab_rails['gitlab_shell_ssh_port'] = 8022第四步:修改邮箱 ...

July 10, 2019 · 1 min · jiezi

Chrome-控制台常用调试技巧详解

1、Chrome控制台小技巧打开和关闭抽屉式选项卡:按Esc键可打开和关闭 DevTools 的 Drawer(抽屉式选项卡) 在Drawer(抽屉式选项卡)中,你可以在 Console 控制台中执行命令,查看动画检查器(Animations),配置网络条件(network conditions)和渲染(rendering)设置,搜索(search)字符串和文件等 使用Request blocking 阻塞请求: 使用这个功能可以拦截请求;比较常用的场景是,页面执行完某操作后页面就进行重定向跳转了,这时如果想调试重定向前发的请求做了啥,就可以使用此功能进行阻塞拦截 debugger:代码手动编程设置断点调试;Coverage 代码覆盖率检测:可以观察到代码覆盖率,哪些是没用的,去除无用代码,较少代码体积Changes 变化:显示更改代码的比较,可以通过这个工具观察你用控制台修改过的代码,类似于git 的 diff 功能类似,红色代表删除、绿色代码新增;Snippets:在 console 里可以临时运行代码,但是书写格式不太友好,而且一换行就执行了(虽然可以 shift+enter 换行),不想打开代码编辑器怎么办,可以使用 Snippets 这个工具创建js脚本,并可以访问和从任何页面的Chrome DevTools面板中执行(除非你删除)。 2、console控制台命令$_:返回最近一次计算的表达式的值;$(selector):返回匹配指定CSS选择器的第一个DOM元素的引用,实际是document.querySelector()函数的别名;$$(selector):$\$(selector)返回一个与给定CSS选择器匹配的元素数组,等效于调用document.querySelectorAll();$x(path):返回一个与给定XPath表达式匹配的DOM元素的数组;clear(): 清除控制台中所有历史记录;copy(object):将指定对象的字符串表示复制到剪贴板;debug(function):当调用指定的函数时,调试器被调用并在Sources(源文件)面板上的函数内部断点暂停;dir(object):Console API的console.dir()方法的别名。getEventListeners(object)返回在指定对象上注册事件的监听器keys(object) 返回一个数组,该数组包含属于指定对象的属性名;values(object):回一个数组,该数组包含属于指定对象的属性值;document.body.contentEditable=true:将浏览器变成编辑器monitorEvents(document.body, "click"):第一个参数是要监听的对象。如果未提供第二个参数,所有事件都会返回。要指定要监听的事件,传递一个字符串或字符串数组作为第二个参数;unmonitorEvents(document.body):停止监听body对象上的事件; 3、console API详解有开发就有console,开发调试必使用的一大命令console,看看都有些啥? (1)输出信息基本方法:console.log 用于输出普通信息console.info 用于输出提示性信息console.error用于输出错误信息console.warn用于输出警示信息console.group&&console.groupEnd分组输出,console.groupCollapsed创建新分组console.group('warn警告信息') console.warn('warn1') console.warn('warn2') console.warn('warn3')console.groupEnd()console.group('info信息') console.warn('info') console.warn('info1')console.groupEnd()console.group('log信息') console.warn('log1') console.warn('log2')console.groupEnd()console.group('error信息') console.warn('error1') console.warn('error2')console.groupEnd() 给console输出添加样式(通过背景属性图片也可以输出哦)['log','info','warn','error'].forEach(item => { let $print = console[item]; console[item] = function() { $print.call(console, '%c'+Array.prototype.slice.apply(arguments).join(' '), 'font-size: 16px;padding:10px;font-weight: bold;text-decoration: underline;') }}) (2)复杂类型输出:console.dir | console.dirxml:替代for in详细的输出对象信息,经常遇到的坑点是,使用console.log想打印出对象信息,发现只有[object Object],现在可以使用dir;dirxml如果可以会使用xml形式打印。 ...

July 9, 2019 · 1 min · jiezi

iOS多渠道统计方法解析

总所周知,iOS 是一个封闭的系统环境,当应用程序需要向外部请求或接收数据时,大部分都需要经过权限认证,否则无法获取到数据。更何况 iOS 本身就无法使用渠道包统计数据,iOS 企业签名包在上传服务器后更是难以引流下载。在这种情况下,如何给多个渠道做推广以及效果统计,是令不少开发者和运营人员头疼的问题。 从技术上,我们要实现 App Store 应用以及 iOS 企业签名包的多渠道推广效果统计。简单来说,包括各个推广渠道下用户的点击、注册、安装等运营推广数据的获取。 方案一:苹果官方统计(iTunes Connect) 在数据权威性上,苹果官方的统计工具必然最权威,也最值得信赖。 登录苹果的官方统计平台 iTunes Connect,在“App分析”模块可以很方便的查看到应用的“展示次数、购买量”等基础数据。 当然,App 推广往往需要多个渠道同时进行,由于 App Store 无法制作渠道包统计,因此 iTunes Connect 也很方便的提供了渠道链接统计服务。只需要在“App分析”的“来源”中点击“营销活动”,右上角有个“生成营销活动链接”,进入后就能自定义设置对应的唯一标识,给每个渠道生成专属的渠道链接。 拿着对应的链接去推广,虽然可以追踪到不同渠道下的精准来源,但 iTunes Connect 的统计也存在许多问题: 只有当营销活动启动后超过一天时间(最长72个小时)后才能显示相关数据;至少有 5 个 App 安装量归因于此营销活动时,营销活动才会在“App 分析”中显示;iOS 8.0 及以上版本的用户可以选择是否将自己的应用使用情况的数据发送给 Apple;iTunes Connect 的统计无法同时兼容 Android 和 iOS,采用不同的统计方法可能会让数据统一性较差。方案二:填写渠道识别码统计(邀请码/渠道码)由于苹果统计数量少时无法展示,以及数据延时性等特性,实际应用中并不适合用来统计地推、邀请有奖等 App 推广场景。 于是在业务流程上,传统做法是让用户填写渠道码来实现业绩统计,比如“老带新”活动中的填写邀请码流程、地推活动中的填写地推码流程等,其本质就是通过获取某个用户填写的专属渠道识别码,来判断用户由哪个渠道邀请来,从而统计推广业绩并发放奖励。 但这种做法会使实际推广中多出一个人工填写的操作流程,高门槛必定导致高流失,用户会产生排斥心理,推广效果也就大打折扣。 方案三:采用第三方SDK追踪以 openinstall 为例,这也是基于渠道链接统计的一种方法,与 iTunes Connect 营销活动链接统计的区别在于: 统计数据能实时反馈并显示;没有数据数量限制,无论采集的样本量多少都能实时显示;能够程序化生成海量专属渠道链接,无需人工定义渠道识别信息;可以同时统计 Android、iOS(包括企业签名) App,数据更有具统一性。同时,由于渠道链接统计的方式具有更高的灵活性,采用 openinstall 可以在不用制作渠道包、填写邀请码的情况下,识别渠道安装来源。这也意味着,开发者甚至能在业务流程上实现免填邀请码、免填地推码统计渠道业绩的需求。 另一方面,在实际应用中,由于能够程序化生成海量渠道链接的特点,可以有效解决 iOS 多渠道统计的难题,主要应用于移动广告效果统计、社交分享效果统计、iOS(包括企业签名)引流与统计、邀请层级关系的建立等方面。 总结:毋庸置疑,苹果官方统计工具在 iOS 领域必然是最优的统计方案,但客观存在的一些弊端在实际应用中也是不可避免的,可以考虑用第三方 openinstall 做这方面的补充。 ...

July 9, 2019 · 1 min · jiezi

深入前端彻底搞懂浏览器运行机制

浏览器是多进程的 Browser进程:浏览器的主进程(负责协调、主控),只有一个。 负责浏览器界面显示,与用户交互。如前进,后退等 负责各个页面的管理,创建和销毁其他进程 将Renderer进程得到的内存中的Bitmap,绘制到用户界面上 网络资源的管理,下载等 第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建 GPU进程:最多一个,用于3D绘制等 浏览器渲染进程(浏览器内核)(Renderer进程,内部是多线程的):默认每个Tab页面一个进程,互不影响。主要作用为页面渲染,脚本执行,事件处理等 新建页面都会开启一个新的进程上面的进程会辅助这个进程的执行,其中渲染进程对页面的影响最重要 怎么查看浏览器进程情况打开Chrome Shift+Esc;我们可以看到进程情况,Chrome图标就是Browser主进程 多线程优缺点避免单个page crash影响整个浏览器 避免第三方插件crash影响整个浏览器 多进程充分利用多核优势 方便使用沙盒模型隔离插件等进程,提高浏览器稳定性 简单点理解:如果浏览器是单进程,那么某个Tab页崩溃了,就影响了整个浏览器,体验有多差;同理如果是单进程,插件崩溃了也会影响整个浏览器;而且多进程还有其它的诸多优势,当然内存等资源消耗也会更大 重点是浏览器内核(渲染进程)该进程有多个线程完成GUI渲染线程负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等。当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行注意,GUI渲染线程与JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起(相当于被冻结了),GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。 JS引擎线程也称为JS内核,负责处理Javascript脚本程序。(例如V8引擎)JS引擎线程负责解析Javascript脚本,运行代码。JS引擎一直等待着任务队列中任务的到来,然后加以处理,一个Tab页(renderer进程)中无论什么时候都只有一个JS线程在运行JS程序同样注意,GUI渲染线程与JS引擎线程是互斥的,所以如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞。 事件触发线程归属于浏览器而不是JS引擎,用来控制事件循环(可以理解,JS引擎自己都忙不过来,需要浏览器另开线程协助)当JS引擎执行代码块如setTimeOut时(也可来自浏览器内核的其他线程,如鼠标点击、AJAX异步请求等),会将对应任务添加到事件线程中当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理注意,由于JS的单线程关系,所以这些待处理队列中的事件都得排队等待JS引擎处理(当JS引擎空闲时才会去执行) 定时触发器线程传说中的setInterval与setTimeout所在线程浏览器定时计数器并不是由JavaScript引擎计数的,(因为JavaScript引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确)因此通过单独线程来计时并触发定时(计时完毕后,添加到事件队列中,等待JS引擎空闲后执行)注意,W3C在HTML标准中规定,规定要求setTimeout中低于4ms的时间间隔算为4ms。 异步http请求线程在XMLHttpRequest在连接后是通过浏览器新开一个线程请求将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件,将这个回调再放入事件队列中。再由JavaScript引擎执行。 进程间的通信过程Browser进程收到用户请求,首先需要获取页面内容(譬如通过网络下载资源),随后将该任务通过RendererHost接口传递给Render进程Renderer进程的Renderer接口收到消息,简单解释后,交给渲染线程,然后开始渲染渲染线程接收请求,加载网页并渲染网页,这其中可能需要Browser进程获取资源和需要GPU进程来帮助渲染当然可能会有JS线程操作DOM(这样可能会造成回流并重绘)最后Render进程将结果传递给Browser进程Browser进程接到结果并将结果绘制出来 渲染进程(浏览器内核)线程的关系GUI渲染线程与JS引擎线程互斥由于JavaScript是可操纵DOM的,如果在修改这些元素属性同时渲染界面(即JS线程和UI线程同时运行),那么渲染线程前后获得的元素数据就可能不一致了。因此为了防止渲染出现不可预期的结果,浏览器设置GUI渲染线程与JS引擎为互斥的关系,当JS引擎执行时GUI线程会被挂起,GUI更新则会被保存在一个队列中等到JS引擎线程空闲时立即被执行。 JS阻塞页面加载从上述的互斥关系,可以推导出,JS如果执行时间过长就会阻塞页面。譬如,假设JS引擎正在进行巨量的计算,此时就算GUI有更新,也会被保存到队列中,等待JS引擎空闲后执行。然后,由于巨量计算,所以JS引擎很可能很久很久后才能空闲,自然会感觉到巨卡无比。所以,要尽量避免JS执行时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。 WebWorker,JS的多线程JavaScript引擎是单线程运行的,JavaScript中耗时的I/O操作都被处理为异步操作,它们包括键盘、鼠标I/O输入输出事件、窗口大小的resize事件、定时器(setTimeout、setInterval)事件、Ajax请求网络I/O回调等。当这些异步任务发生的时候,它们将会被放入浏览器的事件任务队列中去,等到JavaScript运行时执行线程空闲时候才会按照队列先进先出的原则被一一执行,但终究还是单线程。 创建Worker时,JS引擎向浏览器申请开一个子线程(子线程是浏览器开的,完全受主线程控制,而且不能操作DOM)JS引擎线程与worker线程间通过特定的方式通信(postMessage API,需要通过序列化对象来与线程交互特定的数据) //主线程 main.jsvar worker = new Worker("worker.js");worker.onmessage = function(event){ // 主线程收到子线程的消息};// 主线程向子线程发送消息worker.postMessage({ type: "start", value: 12345});//web worker.jsonmessage = function(event){ // 收到};postMessage({ type: "debug", message: "Starting processing..."});浏览器渲染流程拿到内容浏览器根据 DNS 服务器得到域名的 IP 地址向这个 IP 的机器发送 HTTP 请求服务器收到、处理并返回 HTTP 请求浏览器得到返回内容解析内容建立Rendering Tree解析HTMl构建domdom作用: HTMLDOM是HTML Document Object Model(文档对象模型)的缩写,HTML DOM则是专门适用于HTML/XHTML的文档对象模型。熟悉软件开发的人员可以将HTML DOM理解为网页的API。它将网页中的各个元素都看作一个个对象,从而使网页中的元素也可以被计算机语言获取或者编辑。dom规定整个文档是一个文档节点每个HTML标签是一个元素节点包含在HTML元素中的文本是文本节点每一个HTML属性是一个属性节点(属性节点是另一个层面的理解,在浏览器后台打印的时候,不存在属性节点)注释属于注释节点解析过程:浏览器会自动把HTML文档解析为一个“文档对象模型”,即Document Object Model,简称DOM,这是一个树形结构,树根是Document对象,树干是网页的根元素<html>,然后分出两个枝丫,一个是<head>,一个是<body>,然后网页上的其他标签就是这棵树上的树叶和树枝了,通过这个结构,就可以查找和控制网页上的任何一个元素了。因此,可以这么说,网页上的任何元素都是Document对象的子对象。 ...

July 9, 2019 · 1 min · jiezi

Pinbox-集网页收集和跨平台书签管理于一身的效率工具

我们在浏览网页时,遇到有用的或者感兴趣的就想把它收藏起来,可能你的第一反应是点击浏览器的收藏按钮,把它加到书签里,但是如果收藏过多就会像这样 密密麻麻的一片,看着都眼花,找起来也费劲,并且不能跨平台使用,比如在360浏览器收藏,换了个浏览器就看不到那些收藏了。管理起来也不方便,并且浏览器书签只能收藏网站,如果想要收藏一张图片或者一段文字怎么办呢?今天就给大家推荐一款小众但又具有强大功能的高颜值效率工具 Pinbox,也是我亲身试用了一段时间后想要推荐给大家的。 Pinbox 自身定位是一款跨平台的收藏工具,可以用它来记录灵感,稍后阅读,保存资料甚至网络上的任何内容。我使用 Pinbox 之后以上困扰我的问题都迎刃而解了,多级收藏集解决分类管理问题;可以在任何浏览器打开解决跨平台问题,也有安卓和 IOS 软件,一端收藏,多端迅速同步;天然支持收藏网页、图片、文本功能; 当然 Pinbox 不止仅有这些功能,能打动我的,必定有其过人之处,下来我具体介绍一下 Pinbox 的实用功能 界面颜值  在现在这个看脸的时代,颜值也是很重要的,第一印象不好,那基本没有然后了Pinbox 作为一款工具类软件,他的界面风格却不是传统的死板,而做到了简约,轻盈,给人一种赏心悦目的感觉 Pinbox 使用具有神秘而高贵的紫色作为主题色。 简单的文字,平滑的过渡色,使得界面干净而又不失美观 收藏方式 Pinbox 提供两种收藏方式 手动添加点击右上角的加号,可以添加网页,图片和文本安装 Pinbox 扩展 (推荐使用)使用 Pinbox 扩展,就可以一键收藏基本大多数浏览器都支持 在要收藏的网页上右键点击收藏或者直接点击 Pinbox 扩展的 Icon 可以一键收藏到Pinbox 快捷键 收藏的网页肯定是要打开看的,对于常用的网页 Pinbox 支持设置快捷键,一键打开我的快捷键 收藏管理和展示 Pinbox 支持创建多级收藏集,这样可以很方便的将收藏进行分类,拖拽收藏可以快速移动到不同的收藏集收藏的展示分为三种方式,默认是卡片形式,还有列表和极简模式对于收藏电影但来说,卡片形式更好一点,它会显示电影封面收藏来源记录和信息Pinbox 很贴心的将每一个收藏的来源都记录下来,比如收藏一个图片,我们可以轻易的找到这个图片是来自哪个网站的,同时也记录了收藏时间和阅读的次数 导入和导出 Pinbox 可以快速导入浏览器书签和将自己的收藏导出为浏览器书签导出功能在用户中心 收藏集分 享精彩内容需要大家一起看到,分享使人快乐,我们整理了有用的内容,可以分享给朋友或者网友们,Pinbox  可以将自己的收藏集公开,这样别人也可以看到你的精彩的内容只需打开分享开关我整理的电影台词,给大家看看:https://withpinbox.com/explor...以上是我使用过程中觉得好的并且常用的功能,还有很多功能比如搜索,批量操作,回收站等都是非常实用的,就不做一一介绍了。大家有收藏需求,有和我一样被浏览器书签困扰的可以使用 Pinbox ,好的东西需要大家支持和分享让更多的人看到。

July 8, 2019 · 1 min · jiezi

开发一个基于-Vue20-的个人天气预报

本场 Chat 是一个基于 Vue 的个人天气预报项目,就是兴趣所致,做来玩玩。顺便扩展一下知识面。 本项目会采用高德地图 API,Echarts 可视化库和 Vue 相关的技术来开发本项目。有兴趣的同学,可以一起来玩玩。 本场 Chat 你将学到如下内容: 学会制作自己的天气预报;学会使用部分高德地图的 API;学会使用 Echarts的部分 API;Vue+Webpack 相关的一些技术。有兴趣的请到gitchat查看: https://gitbook.cn/gitchat/ac... 效果图如下:

July 5, 2019 · 1 min · jiezi

VueBetterScroll-实现多Tab上拉加载更多实例

本场 Chat 是讲一个基于 Vue+Better-Scroll 实现多 Tab 切换上拉加载更多的实例,像这种多 Tab 切换加载更多的场景,不管在 PC 端还是移动端都还挺常见的,比如商城类,订单中心等。本人在项目中也经常用这种,已经轻车熟路了,所以就想做个总结出来,并做成一个实例 Demo,把经验分享出来,供同样有所需的前端同学学习。 本项目使用 Vue 和 Better-Scroll 相关的技术来开发本项目。通过学习本项目,你也可以做出多 Tab 切换上拉加载更多的效果,而不必到处找别人的例子。 本场 Chat 你将学到如下内容: 学到 Better-Scroll的相关知识;学到 Vue 开发的相关知识;学到用 Vue+Better-Scroll实现多 Tab 切换上拉加载更多。有兴趣学习的可以请到gitchat查看: https://gitbook.cn/gitchat/ac... 效果图如下:

July 5, 2019 · 1 min · jiezi

仿美团城市选择器的-Vue-插件开发实例

本文是讲一个基于 Vue 的仿美团城市选择器的插件开发实例,目前关于城市选择器的插件比较少,在自己做项目的时候一直没有找到合适的城市选择器插件,所以自己开发了一个。同时也想把这个插件分享给出来,供同样有所需的前端同学学习使用。 本项目使用 Vue 和 Vue 插件相关的技术来开发本项目。通过学习本项目,不仅可以拥有自己的城市选择器插件,还可以学到 Vue 插件的开发过程以及 NPM 发布包的相关知识。 通过本吻你将学到如下内容: 学会制作自己的城市选择器;学习 Vue 插件的开发过程;学习如何将制作的插件发布到 NPM。请到gitchat查看 https://gitbook.cn/gitchat/ac... 效果图如下:

July 5, 2019 · 1 min · jiezi

console中的d-s等占位符

前端开发中经常用到浏览器的console控制台,而在console.log和console.debug中有时候可以看见%d %s这样的符号,其意义和用法如下 占位符含义%s for a String value 代表字符串%d 或 %i for a Integer value 代表整数%f for a Floating point number 代表浮点数%o for an Object hyperlink 代表对象的超链接例子var name = "David";var num = 24;var height = 180.5;var obj = { job: 'web developer',};console.log('%s is %d years old, and he is %fcm tall.\nMore details in: %o', name, num, height, obj); 参考https://stackoverflow.com/que...https://blog.csdn.net/linusc/...

July 4, 2019 · 1 min · jiezi

我为什么放弃Pocket使用Pinbox来整理收藏碎片化知识

在收藏这一块,Pocket可以说是算得上老大了,也是我用了好多年的一款收藏App,pocket 主要是用作稍后阅读,但我为什么放弃pocket转到pinbox呢? pocket是国外的产品,在国内访问时速度是真的慢,有时候急需找到收藏的东西却始终打不开网站,除非使用梯子,于是就想找找有没有国产的替代品。然后发现了收趣,方片,试了一下,收趣虽然是打着收藏的口号但更像是一个资讯软件,推送各种广告和没有价值的娱乐新闻,方片还可以,,没有那么多花里胡哨的东西,但是好像已经不更新维护了,然后又继续找,终于发现了 Pinbox,首先看到pinbox官网就感觉是很专业很认真的一款产品,然后看了他们的更新日志,保持基本一周一更的样子 Pinbox 官网地址:https://withpinbox.com 基本的功能都有,可以收藏网页,图片,文本 支持编辑标题和备注,可以创建多级收藏集,可以快速搜索,支持导入/导出备份 支持跨平台支持 网页 + 浏览器扩展 + App,这样就可以同步使用了,在 PC 上收藏的东西可以在手机上打开 收藏方法也很简单,安装 pinbox 的浏览器扩展,然后在想要收藏的网页上右击鼠标就可以收藏了 pinbox 还有一个很好用的功能,可以给收藏添加快捷键,这样就可以不用打开pinbox直接按快捷键就能打开收藏的内容了 inbox 网站风格整体给人感觉很简约轻盈,没有多余花哨的内容,很认真专一的做着该做的事情 收藏可以用三种模式显示,有卡片模式,列表模式和极简模式,按自己的喜好设置就行 国产软件真是越来越好了,没想到Pinbox这么好用还好看,目前还没有发现收费功能,想支持一下,希望能一直做下去 喜欢收藏整理文章,图片和文本的小伙伴赶紧用起来吧,Pinbox 你值得拥有!

July 4, 2019 · 1 min · jiezi

使用Angular7开发一个Radio组件

一、准备工作Angular7(以下简称ng7),已经跟之前版本大有不同。新建工程后,可方便创建library(简称lib),lib是什么呢?就是一个npm包的源码包。npm作为强大的包管理器,已经成为很多FEer分享智慧成果的法器。本文主要介绍本人写的一个radio组件。 二、开发组件radio过程1、使用ng cli,新建工程,创建lib// 安装ng clinpm install -g @angular/cli// 新建工程ng new ng-project// 进入ng-project 创建一个libng generate library radio2、生成结构如图所示 接下来开始写组件 3、radio结构如下<!--说明:这其实是一个radio-group 因为radio一般都是分组使用,这里有几个注意点1、组内radio的name属性保持一致、组外保持唯一2、通过checked属性来设置radio的选中状态,一定不要写成[attr.checked]--><div class="input-wrap" [class.hor]="horizontal"> <div class="custom-radio" *ngFor="let item of data; let i=index"> <input #input class="custom-input" [name]="name" id="{{'radio_'+name+i}}" type="radio" [value]="item.value" (click)="clickHandler(item.value)" [checked]="item.value === value" [disabled]="disabled"> <label class="custom-label" for="{{'radio_'+name+i}}">{{item.name}}</label> </div></div>4、radio组件主体代码如下export class RadioGroupComponent implements ControlValueAccessor { /* radio 数组 */ @Input() data: Radio[] = []; /* radio 类型 原生或者按钮类型*/ @Input() type: string; /* name标识 */ @Input() name: string = this.idSer.generate().replace(/-/g, '_'); /* 水平排列 */ @Input() horizontal: boolean; /* 禁用 */ @Input() disabled: boolean; /* radio 值 */ @Input() value: any; constructor(private idSer: IdService) { } clickHandler(val: any) { this.value = val; // 更改control的值 this.controlChange(this.value); this.controlTouch(this.value); } writeValue(value: any): void { this.value = value; } registerOnChange(fn: Function): void { this.controlChange = fn } registerOnTouched(fn: Function): void { this.controlTouch = fn } private controlChange: Function = () => { } private controlTouch: Function = () => { }}说明:其实组件代码不是很多,但是应该注意到,我们继承了ng的一个interface ControlValueAccessor,这里我觉的是比较值得侃的地方。这是ng的一个forms API,可以方便原生DOM和ng forms传值。在组件元数据中这样定义 ...

July 2, 2019 · 1 min · jiezi

iOS-App渠道统计跟踪方法

说起 iOS 的渠道统计,不少人会想到苹果官方的 App 分析功能(iTunes Connect),但实际操作中我们会发现,这个服务的统计维度还不够全面,许多广告主和运营人员更关心的是各个推广渠道实际带来的安装量、注册量等数据,毕竟这对渠道引流的分析价值更大。iOS的“渠道”通常是指那些在其它 App 或者网页内部,提供到达 App Store 的链接的页面。因此,在 iOS 中追踪发行渠道,主要是追踪进入 App Store 相关页面的渠道信息。 从技术角度来看,也就是在用户首次下载时不仅要获取下载来源,还要实现参数传递,简单来说,就是用户第一次下载后,我能得知后续的注册、活跃、付费等操作行为。或者在此基础上,实现场景还原,帮助用户在首次打开 App 后直接跳转进指定页面,而不是首页。 方案一:苹果官方自带的统计工具 iTunes Connect 登录 iTunes Connect ,在“App 分析”中,能很方便的查看 App 的展示次数、购买量等基础数据,但无法获取更加详细的安装量、注册量等运营数据。 当然,往往 App 推广的渠道会有很多同时进行,怎么对多个渠道的来源做分析呢?同样在“App分析”的“来源”中点击“营销活动”,右上角有个“生成营销活动链接”,进入后就能自定义给每个渠道生成对应的唯一标识。 这种方法虽然可以追踪到多个渠道的来源,但存在以下几个问题: 只有当营销活动启动后超过一天时间(最长72个小时)后才能显示相关数据;至少有 5 个 App 购买量归因于此营销活动时,营销活动才会在“App 分析”中显示;统计的维度不完整,仅限“展示次数”、“App 购买量”、“销售额”、“App 使用次数”四个;iOS 8.0 及以上版本的用户可以选择是否将自己的应用使用情况的数据发送给Apple。方案二:使用 SFSafariViewController 传递参数SFSafariViewController 是 iOS 9.0 出现的,可以通过 Safari 对应的 cookier 传递参数,跨App与Safari共享数据。但是 openurl 失败率还是很高,并且有系统版本、浏览器等限制,比如微信等第三方 App 的内置浏览器就不能很好实现。 方案三:通过 IDFA 进行追踪,比如 Google Analytics常用的比如谷歌官方的 Google Analytics,它的获取原理就是通过获取设备的 IDFA ,来作为唯一标示符号,然后根据你的渠道来源提供数据,通过比对的方式进行渠道定位。弊端在于,用户重置系统,或者关闭广告跟踪的话,这种方法就会失效。 ...

June 27, 2019 · 1 min · jiezi

数据可视化初学者指南定义示例和学习资源

数据可视化是信息和数据的图形表示。通过使用图表,图形和地图等可视元素,数据可视化工具提供了一种可访问的方式来查看和理解数据中的趋势,异常值和模式。在大数据领域,数据可视化工具和技术对于分析大量信息和制定数据驱动决策至关重要。 轻松地给各类图添加或输入数据Visual Paradigm Online 提供了一个非常方便的图表编辑编辑器。只需转到图表制作者,即可从模板创建条形图。它将弹出一个数据表供您输入数据和类别。输入您的数据,您的更改将立即显示在表格旁边的条形图上。 自定义图表颜色和字体在条形图中为条形选择您喜欢的颜色。您还可以调整图表大小或缩放以适合任何维度。所有这一切都可以通过几次点击完成。 轻松缩放或调整条形图的大小想要将条形图添加到报告或演示文稿中吗?您可以将图表调整大小或缩放到任何尺寸,适合任何页面或幻灯片。只需拖动图表的边缘或角落即可调整其大小。 与您的同事协作Visual Paradigm Online是一个在线图表创建者。只需创建一个在线工作区并开始与同事一起创建图表。您的所有作品都保存在云端,因此您可以随时随地访问它们。 更多图表和图表您可以使用Visual Paradigm Online创建各种图表。点击下面的图表了解更多详情。 柱形图 折线图 饼形图 甜甜圈图 条形图 面积图 散点图 气泡图 雷达图 画报图 金字塔图表 漏斗图 仪表图 径向图 玫瑰图 热图 树地图

June 27, 2019 · 1 min · jiezi

WebRTC介绍

一、 WebRTC是什么WebRTC,名称源自网页即时通信(英语:Web Real-Time Communication)的缩写,是一个支持网页浏览器进行实时语音对话或视频对话的API。它于2011年6月1日开源并在Google、Mozilla、Opera支持下被纳入万维网联盟的W3C推荐标准。简单说就是一个音视频处理+及时通讯的开源库。 二、WebRTC 有哪些优点Google开源的框架(背景强大)跨平台(适合当下软件开发的趋势)用于浏览器实时传输音视频引擎(迎合当下的发展趋势)三、WebRTC应用场景音视频会议在线教育照相机音乐播放器共享远程桌面录制即时通讯工具P2P网络加速文件传输工具游戏实时人脸识别由上方列出的条目可以看出,WebRTC的应用场景十分广泛,尤其是在网路越来越发达的当下,音视频会议、在线教育、即时通讯工具、游戏、人脸识别一定是当下和未来的发展方向,跟上时代的步伐才不至于死在沙滩上。 四、 WebRTC的愿景网络传输音视频引擎内网链接音频引擎P2P传输视频引擎TURN中转 五、 WebRTC运行机制 轨与流Track(一路音频/视频就是一路轨)MediaStream (媒体流包含很多轨)WebRTC的重要类MediaStreamRTCPeerConnection(该类很重要,提供了应用层的调用接口)RTCDataChannel (非音视频数据通过它传输)六、 WebRTC目前支持的浏览器Chrome(谷歌)Safari(苹果)FirefoxEdge (微软)七、学习WebRTC的难点WebRTC庞大、烦杂门槛高,全是英文文档,对学习者是一个挑战客户端与服务器分离,增加学习难度网络屏蔽/系统的学习资料少(这个是因为一些大家都懂的原因,对学习者是一个障碍,需要翻墙)网上虽然有demo,但是网上demo错误多,难以调试通八、特此说明以上是对慕课网上WebRTC入门课程的学习资料的整理归纳。

June 27, 2019 · 1 min · jiezi

当谈论迭代器时我谈些什么

花下猫语:之前说过,我对于编程语言跟其它学科的融合非常感兴趣,但我还说漏了一点,就是我对于 Python 跟其它编程语言的对比学习,也很感兴趣。所以,我一直希望能聚集一些有其它语言基础的同学,一起讨论共通的语言特性间的话题。不同语言的碰撞,常常能带给人更高维的视角,也能触及到语言的根基,这个过程是极有益的。 这篇文章是群内 樱雨楼 小姐姐的投稿,她是我们学习群里的真·大佬,说到对 Python 的研究以及高阶知识的水平,无人能出其右(群里很多同学都被她实力圈粉啦)。除了 Python,她对 C++、Perl、Go 与 Fortran 等语言都有涉猎,本文主要是对比了 Python 与 C++,来深入谈谈迭代器。话不多说,请看正文。 樱雨楼 | 原创作者 豌豆花下猫 | 编辑润色 本文原创并首发于公众号【Python猫】,未经授权,请勿转载。 原文地址:https://mp.weixin.qq.com/s/Be... 0 前言迭代器(Iterator)是 Python 以及其他各种编程语言中的一个非常常见且重要,但又充满着神秘感的概念。无论是 Python 的基础内置函数,还是各类高级话题,都处处可见迭代器的身影。 那么,迭代器究竟是怎样的一个概念?其又为什么会广泛存在于各种编程语言中?本文将基于 C++ 与 Python,深入讨论这一系列问题。 1 什么是迭代器?我们为什么要使用迭代器?什么是迭代器?当我初学 Python 的时候,我将迭代器理解为一种能够放在“for xxx in ...”的“...”位置的东西;后来随着学习的深入,我了解到迭代器就是一种实现了迭代器协议的对象;学习 C++ 时,我了解到迭代器是一种行为和指针类似的对象... 事实上,迭代器是一个伴随着迭代器模式(Iterator Pattern)而生的抽象概念,其目的是分离并统一不同的数据结构访问其中数据的方式,从而使得各种需要访问数据结构的函数,对于不同的数据结构可以保持相同的接口。 在很多讨论 Python 迭代器的书籍与文章中,我看到这样两种观点:1. 迭代器是为了节约数据结构所产生的内存;2. 遍历迭代器效率更高。 这两点论断都是很不准确的:首先,除了某些不定义在数据结构上的迭代器(如文件句柄,itertools 模块的 count、cycle 等无限迭代器等),其他迭代器都定义在某种数据结构上,所以不存在节约内存的优势;其次,由于迭代器是一种高度泛化的实现,其需要在每一次迭代器移动时都做一些额外工作(如 Python 需要不断检测迭代器是否耗尽,并进行异常监测;C++ 的 deque 容器需要对其在堆上用于存储的多段不连续内存进行衔接等),故遍历迭代器的效率一定低于或几乎接近于直接遍历容器,而不太可能高于直接遍历原容器。 综上所述,迭代器存在的意义,不是为了空间换时间,也不是为了时间换空间,而是一种适配器(Adapter)。迭代器的存在,使得我们可以使用同样的 for 语句去遍历各种容器,或是像 C++ 的 algorithm 模块所示的那样,使用同样的接口去处理各种容器。 ...

June 27, 2019 · 2 min · jiezi

chrome插件开发-tab选项卡管理器

1. 前言继上周第一次开发Chrome插件github-star-trend之后,我就一直寻思有什么现实问题可以用插件来解决呢?正当我在浏览器中搜索寻找灵感时,打开的众多tab选项卡令我灵光一闪。 咦,为什么不做一个插件用来管理tab呢?每次同时打开过多的tab选项卡时,被挤压的标题总是让我分不清哪个是哪个,查看起来十分不便。于是乎,经过一个周末下午的折腾,我倒腾出这么个东西(gif图可能有点大,请耐心等待...): 2. 准备工作按照惯例,正式进入主题之前让我们来先了解点预备知识。默默打开Chrome插件的官方文档,直奔我们的Tabs。可以看到它为我们提供了很多方法,而且竟然还有executeScript,这个可以说权限非常大了,不过跟我们这次的需求没啥关系。。。 2.1 query由于我们的需求是管理tab选项卡,所以首先肯定得获取所有的tab信息。扫了一遍Methods,最相关的就是方法query: Gets all tabs that have the specified properties, or all tabs if no properties are specified.正如官方介绍,该方法可以根据指定条件返回相应的tabs;且当不指定属性时,可以获得所有的tabs。这恰好满足我们的需求,按照API指示,我在callback中尝试打印出了拿到的tabs对象: chrome.tabs.query({}, tabs => console.log(tabs));[ { "active": true, "audible": false, "autoDiscardable": true, "discarded": false, "favIconUrl": "https://static.clewm.net/static/images/favicon.ico", "height": 916, "highlighted": true, "id": 25, "incognito": false, "index": 0, "mutedInfo": {"muted":false}, "pinned": true, "selected": true, "status": "complete", "title": "草料文本二维码生成器", "url": "https://cli.im/text?bb032d49e2b5fec215701da8be6326bb", "width": 1629, "windowId": 23 }, ... { "active": true, "audible": false, "autoDiscardable": true, "discarded": false, "favIconUrl": "https://www.google.com/images/icons/product/chrome-32.png", "height": 948, "highlighted": true, "id": 417, "incognito": false, "index": 0, "mutedInfo": {"muted": false}, "pinned": false, "selected": true, "status": "complete", "title": "chrome.tabs - Google Chrome", "url": "https://developers.chrome.com/extensions/tabs#method-query", "width": 1629, "windowId": 812 }]仔细观察不难发现,两个tab的windowId不同。这是由于我在本地同时打开了两个Chrome窗口,而这两个tab恰好在两个不同的窗口内,所以正好符合预期。 ...

June 24, 2019 · 3 min · jiezi

Deeplink深度链接如何提高App转化率留存率

移动互联网时代,信息的分享传播无疑是 App 引流增长的关键,与其花费大量精力和成本找渠道、硬推广,不如从细节下手,用最快最简便的方法实现 Deeplink(深度链接)技术,打破信息孤岛、缩短分享路径、优化用户体验,最终提高流量转化率和留存率。 什么是 DeepLink(深度链接)技术 如果把 App 看成网站,那么 DeepLink 就是网站中的深入页面,比如商品购物页面、活动促销页面。简单理解,就是当用户点击手机中的某个链接时,可以帮他跳转到 App 内部中的目标页面,直接实现场景还原,而不是 App 首页,这是一种无障碍场景还原技术。 DeepLink 通常运用于App社交分享、App广告引流、App裂变活动、Web to App、分享效果统计、沉默用户唤醒等场景,对广告引流、活动推广、新闻类、电商类、游戏类、视频直播类App的引流推广和转化都有着奇效。 升级版 Deferred deeplink(延迟深度链接)技术 相比 Deeplink,Deferred deeplink 增加了一个判断,能在用户点击链接时判断设备是否安装了目标App,如果没有安装,则跳转应用市场或者浏览器中引导下载,用户安装后再次实现 Deeplink 的场景还原功能。 是否使用这两项技术的差别: 可以看到,使用了深度链接后,用户操作成本明显降低了一至两步,做运营的小伙伴都知道,在用户转化的漏斗中,每多一个步骤,漏斗的路径就会多一层,用户流失率也就随之增加。 怎样为App快速实现这两项技术 我们以 openinstall 的一键拉起功能为例,这项功能集成了深度链接中的scheme,universal link等核心技术,能完美实现 Deeplink、Deferred deeplink 的所有技术场景效果,主要特点如下: 一键拉起功能同时兼容 Android、iOS 系统,不存在操作系统技术障碍;适配了大量主流社交平台和浏览器,如微信、QQ、新浪微博、钉钉、支付宝等;用户已安装该 App 的情况下,点击页面链接可直接拉起本地 App,并自动进入目标页面;用户未安装该 App 的情况下,点击页面链接会引导到应用商店或默认浏览器下载,安装后首次打开将自动进入目标页面;该功能目前以及免费开放给所有开发者。openinstall:https://www.openinstall.io/pu... 不仅如此,在深度链接的基础上,还能完善出更多定制化场景需求,比如: 能够根据需求满足开发者业务逻辑,如:既可实现下载优先,也可以实现拉起优先;在社交分享页面上,openinstall 还能同时实现携带参数安装,帮助开发者实现渠道来源统计,具体到用户是被哪篇文章吸引来的、哪个广告页面的转化率最高、哪件产品付费效果最好;甚至可以在业务上实现【社交平台快速下载 App、免填邀请码、App 安装后自动加群加好友、下载 App 后自动登录账号】等功能,进一步完善用户体验和关系链。哪些产品或场景非常适合深度链接 社交平台我们以微信为例,产品以电商类京东 App、资讯类今日头条 App 为例,可以参考他们的结合效果: 显而易见,电商类、资讯类、旅游类、服务类 App 结合社交分享传播具有非常大的价值,此外,游戏类 App 甚至可以利用一键拉起功能点击分享链接直接进入 App 内的游戏房间。 ...

June 21, 2019 · 1 min · jiezi

页面审核工具-Chrome-Lighthouse-简介

作者:Bolaji Ayodeji翻译:疯狂的技术宅 原文:https://www.freecodecamp.org/... 未经允许严禁转载 Chrome Lighthouse 已经存在了一段时间了,但如果我要求你解释一下它能做什么,你能解释清楚吗? 我发现许多 Web 开发人员包括初学者,都没有听说过这个工具,而那些尚未尝试过的人,一点也不酷 ????。 在本文中,我将向你介绍 Chrome Lighthouse 的作用以及如何使用它。 让我们开始吧 ???? 根据维基百科,lighthouse是一座塔楼、建筑物或其他类型的结构,它用灯和镜头系统发出光线,作为海上或内陆水道船舶的导航设备。好吧,让我们把它变成一个技术术语; Lighthouse 是一个塔楼,建筑物或其他类型的结构,它在 Chrome 开发者工具的“审核”面板下的系统发出光线,并作为开发人员的指南有道理吗????? 好吧,Lighthouse 是 Google 开发的一款工具,用于分析网络应用和网页,收集现代性能指标并提供对开发人员最佳实践的意见。 可以将 Lighthouse 看作是汽车中用来检查和平衡汽车速度限制的车速表。 一般情况下 Lighthouse 与开发最佳实践和性能指标一起使用。它在 Web 应用上运行检查,并为你提供有关错误的反馈、低于标准的实践、更好的性能提示以及如何解决这些问题。 根据 Google Developers Docs 上的描述 Lighthouse 是一种开源的自动化工具,用于提高网页质量。你可以在任何网页上运行它。它能够针对性能、可访问性、渐进式 Web 应用等进行审核。你可以在 Chrome DevTools 中从命令行运行 Lighthouse,也可以作为 Node.js 模块运行。当你向 Lighthouse 提供了一个 URL 来进行审核时,它会针对该页面运行一系列审核,然后生成一个关于该页面执行情况的报告。这份报告可以作为如何改进页面的指标。每次审核都会产生一份参考文档,解释了这些审核为什么重要,以及如何解决等内容。 这几乎都与 Lighthouse 有关,它会审核 Web 应用的 URL 并根据 Web 标准和开发人员最佳实践生成一份报告,告诉你 Web 应用的糟糕程度。报告的每个部分还附有文档,说明你的应用哪些部分已经通过审核,为什么你应该改进应用的某一部分以及如何去解决它。 以下是此博客https://bolajiayodeji.com的lighthouse审核报告演示 ...

June 21, 2019 · 2 min · jiezi

FireFox和Safari兼容eventpath

在项目开发中遇到需要获取触发事件元素冒泡过程的所有元素,在Chrome中可以通过event.path获取。 element.onClick(event) { const ev = window.event || event; const path = ev.path;}该属性在Chrome和Opera浏览器下没问题,但是在Firefox和Safari中发现event并没有path属性。 进过查找资料发现,在浏览器新的标准里定义的composedPath可以获取 element.onClick(event) { const ev = window.event || event; const path = event.path || (event.composedPath && event.composedPath()); console.log(path) //[button#btn, div, body, html, document, Window]}

June 18, 2019 · 1 min · jiezi

想让自己的项目6666可是-Chrome-不答应

读万卷书,行万里路!有的技能可以从书里学会,有的技能却需要在实战中打怪升级慢慢掌握,今天就来和大家聊一个很多小伙伴经常遇到的问题。 <!--more--> 缘起有人向松哥反映,在搭建微服务分布式配置中心 Spring Cloud Config 时,如果将端口设置为 6000,总是访问不成功,像下面这样: 如果换成 Tomcat 默认的 8080 就可以访问了。 其实不止 6000,如果你配置成 6666 ,也是无法访问成功的! 分析刚入行或者经验欠缺的小伙伴应该很容易遇到这个问题,松哥就来和大家稍微说一说这个问题。 首先,当我们将项目的端口设置为 6000 之后,并非仅仅只有 Chrome 无法访问,Firefox、Safari 也是无法访问的,反而是经常被大家忽略的坐在角落的 IE/Edge 这对难兄难弟可以访问!看看 Safari 访问 6000 端口怎么说: 再看看 Firefox 访问 6000 端口怎么说: 但是 Edge 就可以访问,如下: 看到这里,大家首先可以确认出现这个问题,和你的代码没有关系!是不是可以松一口气了! 这个问题实际上是由 Chrome 默认的非安全端口限制导致的,除了上文说的 6000,还有其他端口也无法在 Chrome 、Firefox 以及 Safari 中访问(具体端口见文末列表)。 这些无法访问的端口大部分都是小于 1024,小于 1024 的端口大家应该会很少使用,基本上不会在这个上面栽跟头。大于 1024 的端口也并非每一个都可以使用,这才是容易犯错的地方。 解决那么问题要怎么解决呢?两个思路: 修改项目端口(推荐)修改浏览器配置,使之允许访问非安全端口推荐大家使用第一种方案,省事! 如果要使用第二种方案: Chrome 修改办法如下:右键单击Chrome快捷方式 -> 目标 -> 末尾添加参数:--explicitly-allowed-ports=6000 ...

June 17, 2019 · 1 min · jiezi

chrome插件开发-github仓库star趋势图

1. 前言这天,在逛github(就是划水)的时候,突然想看看某个仓库的star走势,但是在star列表中翻了半天愣是没找到相应的功能。于是乎,谷歌一搜,发现有个叫Star History的谷歌插件,然而竟然要收费。。。 于是,又接着搜索,发现了这个仓库。好巧的是,这个仓库就是那个插件的源码。稍微瞅了下源码,感觉我也能行? 由于之前就想学学怎么写chrome插件,本着学习的态度和好奇心驱使(都是划水,没有什么不同),于是也做了一个可以查看仓库Star趋势的插件。效果如下: 2. 准备工作2.1 chrome插件简单入门由于也是第一次写Chrome插件,作为小白,就先搜搜大家都是怎么写chrome插件的吧。果然,一搜一大堆。。。不过,最终还是选择了官方文档,毕竟是第一手资料,虽然是英文,但写得还算通俗易懂,阅读起来没啥问题。 这里推荐看Getting Started,非常友好,一步步教你完成一个最简单的修改网页背景颜色的Chrome插件。跟着教程完成之后你就会发现,原来Chrome插件就像完成一个web项目一样。 manifest.json是项目的配置文件(类似于package.json),插件所需要的一些能力(例如Storage)就在这个文件中声明。剩下的工作,无非就是根据Chrome插件提供的API实现你想要的功能即可。 我们来看下要创建的项目目录和manifest.json配置文件: ├── README.md├── dist│   └── bundle.js├── images│   ├── trending128.png│   ├── trending16.png│   ├── trending32.png│   └── trending48.png├── manifest.json├── package.json├── src│   └── injected.js└── webpack.config.js{ "name": "Github-Star-Trend", "version": "1.0", "manifest_version": 2, "description": "Generates a star trend graph for a github repository", "icons": { "16": "images/trending16.png", "32": "images/trending32.png", "48": "images/trending48.png", "128": "images/trending128.png" }, "content_scripts": [ { "matches": ["https://github.com/*"], "js": ["dist/bundle.js"] } ]}这里需要解释一点,根据最一开始我们看到的效果图,可以发现我们正在浏览的页面上多了一个Star Trend按钮。所以我们要完成的插件需要能够往页面注入一个按钮,而这正是通过manifest.json中的content_scripts字段实现的。它允许我们往matches字段匹配的网页中注入js字段中的脚本文件。 ...

June 17, 2019 · 3 min · jiezi

Python3网络爬虫实战4数据库的安装MySQLMongoDBRedis

上一篇文章:Python3网络爬虫实战---3、解析库的安装:LXML、BeautifulSoup、PyQuery、Tesserocr下一篇文章:Python3网络爬虫实战---5、存储库的安装:PyMySQL、PyMongo、RedisPy、RedisDump作为数据存储的重要部分,数据库同样是必不可少的,数据库可以分为关系型数据库和非关系型数据库。 关系型数据库如 SQLite、MySQL、Oracle、SQL Server、DB2 等,其数据库是以表的形式存储,非关系型数据库如MongoDB、Redis,它们的存储形式是键值对,存储形式更加灵活。 本书用到的数据库主要有关系型数据库 MySQL 及非关系型数据库 MongoDB、Redis。 本节我们来了解一下它们的安装方式。 1.3.1 MySQL的安装MySQL 是一个轻量级的关系型数据库,以表的形式来存储数据,本节我们来了解下它的安装方式。 1. 相关链接官方网站:https://www.mysql.com/cn下载地址:https://www.mysql.com/cn/down...中文教程:http://www.runoob.com/mysql/m...2. Mac下的安装推荐使用 Homebrew 安装,执行 brew 命令即可。 brew install mysql启动、停止、重启 MySQL 服务的命令: sudo mysql.server startsudo mysql.server stopsudo mysql.server restartMac 一般不会作为服务器使用,如果要想取消本地 host 绑定,同样修改 my.cnf 文件,然后重启服务即可。 1.3.2 MongoDB安装MongoDB 是由 C++ 语言编写的非关系型数据库,是一个基于分布式文件存储的开源数据库系统,其内容存储形式类似 Json 对象,它的字段值可以包含其他文档,数组及文档数组,非常灵活。 MongoDB 支持多种平台,包括 Windows、Linux、Mac OS、Solaris 等,在其官方网站均可找到对应的安装包,https://www.mongodb.com/downl... 本节我们来看下它的安装过程。 1. 相关链接官方网站:https://www.mongodb.com官方文档:https://docs.mongodb.comGitHub:https://github.com/mongodb中文教程:http://www.runoob.com/mongodb...2. Mac下的安装推荐使用 Homebrew 安装,执行 brew 命令即可: brew install mongodb然后创建一个新文件夹 /data/db,用于存放 MongoDB 数据。 启动 MongoDB 服务: ...

June 14, 2019 · 1 min · jiezi

Python3网络爬虫实战3解析库的安装LXMLBeautifulSoupPyQueryTesserocr

上一篇文章:Python3网络爬虫实战---2、请求库安装:GeckoDriver、PhantomJS、Aiohttp下一篇文章:抓取下网页代码之后,下一步就是从网页中提取信息,提取信息的方式有多种多样,可以使用正则来提取,但是写起来会相对比较繁琐。在这里还有许多强大的解析库,如 LXML、BeautifulSoup、PyQuery 等等,提供了非常强大的解析方法,如 XPath 解析、CSS 选择器解析等等,利用它们我们可以高效便捷地从从网页中提取出有效信息。 本节我们就来介绍一下这些库的安装过程。 1.2.1 LXML的安装LXML 是 Python 的一个解析库,支持 HTML 和 XML 的解析,支持 XPath 解析方式,而且解析效率非常高。 1. 相关链接官方网站:http://lxml.deGitHub:https://github.com/lxml/lxmlPyPi:https://pypi.python.org/pypi/...2. Mac下的安装pip3 install lxml如果产生错误,可以执行如下命令将必要的类库安装: xcode-select --install之后再重新运行 Pip 安装就没有问题了。 LXML 是一个非常重要的库,后面的 BeautifulSoup、Scrapy 框架都需要用到此库,所以请一定安装成功。 3. 验证安装安装完成之后,可以在 Python 命令行下测试。 $ python3>>> import lxml如果没有错误报出,则证明库已经安装好了。 1.2.2 BeautifulSoup的安装BeautifulSoup 是 Python 的一个 HTML 或 XML 的解析库,我们可以用它来方便地从网页中提取数据,它拥有强大的 API 和多样的解析方式,本节我们了解下它的安装方式。 1. 相关链接官方文档:https://www.crummy.com/softwa...中文文档:https://www.crummy.com/softwa...PyPi:https://pypi.python.org/pypi/...2. 准备工作BeautifulSoup 的 HTML 和 XML 解析器是依赖于 LXML 库的,所以在此之前请确保已经成功安装好了 LXML 库,具体的安装方式参见上节。 3. Pip 安装目前 BeautifulSoup 的最新版本是 4.x 版本,之前的版本已经停止开发了,推荐使用 Pip 来安装,安装命令如下: ...

June 14, 2019 · 2 min · jiezi

前端代码兼容-Chrome-44-的部分操作记录

公司项目原有的代码计划支持到 Chrome 49, 特殊项目需要支持到 Chrome 44. 从网上可以找到 Mac 上的 dmg 安装文件, 这个页面能拿到 Chrome 48,https://www.slimjet.com/chrom... 安装以后需要指定一个目录启动, 否则低版本浏览器读取高版本的配置, 会报错,--profile-directory=chrome-old/ 网上有 Webpack 配置使用 Babel 的详细教程,https://medium.com/@zural143/... 大致安装一些依赖, yarn add --dev @babel/core @babel/plugin-proposal-object-rest-spread @babel/preset-env babel-loader @babel/plugin-syntax-dynamic-importWebpack 部分的配置大致是, { test: /\.js$/, //Regular expression exclude: /(node_modules|bower_components)/,//excluded node_modules use: { loader: "babel-loader", options: { presets: ["@babel/preset-env"], //Preset used for env setup plugins: ["@babel/plugin-proposal-object-rest-spread", "@babel/plugin-syntax-dynamic-import", "@babel/plugin-transform-arrow-functions"], } }}Chrome 48 就已经不支持解构赋值了, 所以需要 Babel 转换,另一个是 Chrome 45 的箭头函数, 很多第三方模块也在用, 需要转换,我们代码当中用到动态 import, 也需要转换.目前主要是这几个. ...

June 14, 2019 · 1 min · jiezi

Python3网络爬虫实战2请求库安装GeckoDriverPhantomJSAiohttp

上一篇文章:Python3网络爬虫实战---1、请求库安装:Requests、Selenium、ChromeDriver下一篇文章:1.1.4 GeckoDriver的安装在上一节我们了解了 ChromeDriver 的配置方法,配置完成之后我们便可以用 Selenium 来驱动 Chrome 浏览器来做相应网页的抓取。那么对于 Firefox 来说,也可以使用同样的方式完成 Selenium 的对接,这时需要安装另一个驱动 GeckoDriver。本节来介绍一下 GeckoDriver 的安装过程。 1. 相关链接GitHub:https://github.com/mozilla/ge...下载地址:https://github.com/mozilla/ge...2. MAC安装方式brew install GeckoDriver3. 验证安装配置完成之后,就可以在命令行下直接执行 geckodriver 命令测试。命令行下输入:geckodriver这时控制台应该有类似输出,如图 1-20 所示: 图 1-20 控制台输出如果有类似输出则证明 GeckoDriver 的环境变量配置好了。随后再在程序中测试,执行如下 Python 代码: from selenium import webdriverbrowser = webdriver.Firefox()运行之后会弹出一个空白的 Firefox 浏览器,证明所有的配置都没有问题,如果没有弹出,请检查之前的每一步的配置。如果没有问题,接下来我们就可以利用 Firefox 配合 Selenium 来做网页抓取了。 4. 结语到现在位置我们就可以使用 Chrome 或 Firefox 进行网页抓取了,但是这样可能有个不方便之处,因为程序运行过程中需要一直开着浏览器,在爬取网页的过程中浏览器可能一直动来动去,着实不方便。目前最新的 Chrome 浏览器版本已经支持了无界面模式,但如果版本较旧就不支持。所以在这里还有另一种方便的选择就是安装一个无界面浏览器 PhantomJS,抓取过程会在后台运行,不会再有窗口出现,这样就方便了很多,所以在下一节我们再了解一下 PhantomJS 的相关安装方法。 1.1.5 PhantomJS的安装如果我们使用 Chrome 或 Firefox 进行网页抓取的话,每次抓取的时候,都会弹出一个浏览器,比较影响使用。所以在这里再介绍一个无界面浏览器,叫做 PhantomJS。PhantomJS 是一个无界面的,可脚本编程的 WebKit 浏览器引擎。它原生支持多种 web 标准:DOM 操作,CSS 选择器,JSON,Canvas 以及 SVG。Selenium 支持 PhantomJS,这样在运行的时候就不会再弹出一个浏览器了,而且其运行效率也是很高的,还支持各种参数配置,使用非常方便,下面我们就来了解一下 PhantomJS 的安装过程。 ...

June 14, 2019 · 1 min · jiezi

实用Javascript调试技巧分享

见过太多同学调试Javascript只会用简单的console.log甚至alert,看着真为他们捉鸡。。因为大多数同学追求优雅而高效地写代码,却忽略了如何优雅而高效地调试代码,不得不说是有点“偏科”了。下面我就分享一些实用且聪明的调试技巧,希望能让大家调试自己代码的时候更加从容自信。 1. 不要使用alert首先,alert只能打印出字符串,如果打印的对象不是String,则会调用toString()方法将该对象转成字符串(比如转成[object Object]这种),所以除非你打印String类型的对象,其他什么信息都获取不到。其次,alert会阻塞UI和javascript的执行,必须点击'OK'按钮才能继续,非常低效。所以,喜欢使用alert的同学可以改改这个习惯了。 2. 学会使用console.logconsole.log谁都会用,但是很多同学只知道最简单的console.log(x)这样打印一个对象,当你的代码里面console.log多了之后,会很难将某条打印结果和代码对应,所以我们可以给打印信息加上一个标签便于区分: let x = 1;console.log('aaaaaaaa', x);得到: 标签不一定要有明确的含义,视觉效果显著就可以了,当然有明确意义更好。 事实上,console.log可以接收任意多的参数,最后将这些对象拼接输出,比如: 如果打印信息过多,不容易找到目标信息的话,可以在控制台中进行过滤: 注意点 在使用console.log打印一个引用类型(比如数组和自定义对象)的对象的时候,输出结果可能并不是执行console.log方法那个时间点的值。举个例子: 可以发现两个console.log输出的结果展开后都是[1, 2, 3, 4],因为数组是引用类型,所以在展开后获取到的都是数组最新的状态。我们可以使用JSON.parse(JSON.stringify(...))来解决这个问题: 3. 学会使用console.dir我们有时候想看看一个DOM对象里面到底有什么属性和方法,但是常规的console.log打印出来的只是HTML标签,就像这样: 和直接审查元素没有什么区别。 如果我们想看到DOM对象作为JavaScript对象的结构可以使用console.dir,比如: 事实上,console.dir可以打印出任何JavaScript对象的属性列表,比如打印一个方法: 4. 学会使用console.table我们经常会遇到这样的场景:获取到一个用户列表,每个用户有很多属性,但是我们只想查看其中的某些属性,在用console.log打印出来的时候需要把每个用户对象展开一个个查看,非常麻烦。而console.table完美的解决这个问题,比如我只想获取到下列用户的id和坐标: console.log打印结果: console.table打印结果: 非常的准确和快速! 5. 学会使用console.time有时候我们想知道一段代码的性能或者一个异步方法需要运行多久,这时候需要用到定时器,JavaScript提供了现成的console.time方法,例如: 6. 使用debugger打断点有时候我们需要打断点进行单步调试,一般会选择在浏览器控制台直接打断点,但这样还需要先去Sources里面找到源码,然后再找到需要打断点的那行代码,比较费时间。使用debugger关键词,我们可以直接在源码中定义断点,方便很多,比如: 7. 查到源码文件有时候我们想在控制台的Sources中查找某个js源文件,要把文件夹逐一点开找,非常麻烦。其实Chrome提供了文件的搜索功能,只不过大部分时候我们给忽略了。。 只要按Command + P(windows的快捷键请自行查看)就能弹出搜索框搜索你想要找的文件啦: 8. 压缩JS文件的阅读有时候我们需要在Sources中阅读一段js代码,但是发现它被压缩了,Chrome也提供了和方便的格式化工具,让代码变得重新可读: 点完之后变成这样: 以上就是我个人在平时比较常用的一些调试小技巧,如果大家有其他好的调试技巧也欢迎分享,谢谢????!

June 14, 2019 · 1 min · jiezi

Python3网络爬虫实战1请求库安装RequestsSeleniumChromeDriver

下一篇文章:爬虫可以简单分为几步:抓取页面、分析页面、存储数据。 在第一步抓取页面的过程中,我们就需要模拟浏览器向服务器发出请求,所以需要用到一些 Python 库来实现 HTTP 请求操作,在本书中我们用到的第三方库有 Requests、Selenium、Aiotttp 等。 在本节我们介绍一下这些请求库的安装方法。 1.1.1 Requests的安装由于 Requests 属于第三方库,也就是 Python 默认不会自带这个库,需要我们手动去安装,下面我们首先看一下它的安装过程。 1. 相关链接GitHub:https://github.com/requests/r...PyPy:https://pypi.python.org/pypi/...官方文档:http://www.python-requests.org 中文文档:http://docs.python-requests.o...2. Pip安装无论是 Windows、Linux 还是 Mac,都可以通过 Pip 这个包管理工具来安装。 在命令行下运行如下命令即可完成 Requests 库的安装: pip3 install requests这是最简单的安装方式,推荐此种方法安装。 3. Wheel安装Wheel 是 Python 的一种安装包,其后缀为 whl,在网速较差的情况下可以选择下载下 Wheel 文件再安装,直接用 pip3 命令加文件名安装即可。 不过在这之前需要先安装 Wheel 库,安装命令如下: pip3 install wheel然后到 PyPi 上下载对应的 Wheel 文件,如当前最新版本为 2.17.3,则打开:https://pypi.python.org/pypi/...,下载 requests-2.17.3-py2.py3-none-any.whl 到本地。 随后命令行进入 Wheel 文件目录,利用 Pip 安装即可。 pip3 install requests-2.17.3-py2.py3-none-any.whl这样我们同样可以完成 Requests 的安装。 4. 源码安装那么如果你不想用 Pip 来安装,或者想获取某一特定版本,可以选择下载源码安装。 ...

June 13, 2019 · 2 min · jiezi

前端答疑chrome开发者工具正确食用看网页源码

写这个文章,是因为在今天早上,有两个兄弟找我要源码。有图有真相。我震惊于都 9102年了,身为了一个正(xie)经(xin)前端er,还不会看控制台? chrome 开发者工具之 Sources打开我们的 Sources 选项看,我们可以看到如下结构。分为三块功能,左(目录)中(资源展示)右(断点调试)。 Sources 工具(左边区域)我们选中 page ,在这个里面我们可以看到我们所有的资源以树状展示。我们在对应的域名下 www.lilnong.top 下,找到 https://www.lilnong.top/static/html/svg-data-background-img-download.html这个路径,点击就可以看到对应的资源 Sources 工具(中间区域)这里就可以看到对应资源详情了,我们都看到源码了,直接复制岂不美滋滋。当然这里还有其他用途,比如说调试代码。作为一个正(wai)气(men)凛(xie)然(dao)的前端er,我们就不发挥一下自己的脑回路? 不知道大家有没有遇到调试线上 Vue 文件的时候遇到 new 出来的对象没绑定到全局拿不到? 方案一 找个方法打个断点,触发一下,然后 this 绑定到 window 。这边我们就可以随心所欲。方案二 找到 el 绑定的 DOM 对象去拿 __vue__大家有玩过网页游戏吗? Console 写个代码?或者说偷偷看一下过关条件?这里也和游戏有关,有一兄弟,爱摸鱼。之前的几款游戏,比较简单,他自己就破解了。游戏一上外挂,就索然无味。 这天,一个 angular 写的游戏,他束手无策,玩了几天,身体日渐消瘦。我决定拯救他一下。 通过我上面写的本领,成功打断点,找到初始化的时候,增加了外置修改器。解救兄弟与水火之间Sources 工具(右边区域)这里是调试工具,下面我们介绍一下每个按钮的功能 当有断点的时候是个,三角,意思是放过这个断点。当无断点的时候会在下次调用的时候停住。下一行,如果是方法不会跳进去步入,如果是方法,可以跳进去步出,跳出当前方法下一步(我没用过)当前状态是捕获调试。蓝色的时候是不捕获调试,会跳过 debugger。方便你打了断点,然后又想测试效果这个是捕获错误。当前是不捕获。chrome 开发者工具之 Network如果说,上一个 Sources工具 基本都是和代码相关的。这个就比较常用了。 看接口的返回值看接口的请求头,响应头查看资源的加载速度查看资源的大小,缓存情况,响应情况(cdn、waiting 等时间) Network 之 preserve log该功能为长日志功能,正常来说看到的都是当前页面的。如果跳转页面或者说刷新之后就没了。通过打开 preserve log,我们可以长久的保留内容。那它有什么作用呢? 我们可以看到一些中间页的跳转,省去了抓包的麻烦。可以和上个页面的数据比对。Network 之 disable cache前端缓存也是比较麻烦的一个事情。经常需要强刷,清缓存一顿的操作。当我们打开 disable cache 之后,我们就不需要关了,每次都是无缓存的加载 Network 之 offline比如说在测试 PWA。或者说弱网的情况下的一种快速配置。 ...

June 6, 2019 · 1 min · jiezi

跨浏览器问题的五种解决方案

简评: 浏览器兼容性问题常常让人头疼,以下是避免出现这些问题的五个技巧。1. 前缀 CSS3 样式如果您正在使用任何类型的现代 CSS 片段,例如框尺寸(box-sizing)或背景剪辑(background-clip),请确保使用适当的前缀。 -moz- /* Firefox and other browsers using Mozilla's browser engine */-webkit- /* Safari, Chrome and browsers using the Webkit engine */-o- /* Opera */-ms- /* Internet Explorer (but not always) */2. 使用 reset您可以使用 normalize.css,下面是我用的,来自 Genesis Framework Style Sheet。 html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,a,abbr,acronym,address,big,cite,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,input,menu,nav,output,ruby,section,summary,time,mark,audio,video {border: 0;margin: 0;padding: 0;vertical-align: baseline;}3. 避免填充宽度当你添加宽度为一个元素的填充时,它会变得更大。宽度和填充将被加在一起。 要解决这个问题,可以添加这个: * { -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */-moz-box-sizing: border-box; /* Firefox, other Gecko */box-sizing: border-box; }4. 清除 float如果没有清除,很容易出问题。感兴趣的可以看看 Chris Coyier 的这篇文章。 ...

June 4, 2019 · 1 min · jiezi

优化-Google-Chrome-的使用体验

优化 Google Chrome 的使用体验吾辈的博客原文 https://blog.rxliuli.com/p/54...前言假若我没有看见光明,我本可以忍受黑暗。下面是吾辈在使用 Chrome 遇到的一些不舒服的地方,以及对应的解决方法。一切皆是为了一个目标:提高浏览器的使用体验! 字体在之前吾辈也未曾对字体有过什么注意,直到后来听闻 MacOS 的字体显示比 Windows 上好很多,去看了一下确实如此。想要有一个好看的字体,字体本身极为重要,这里吾辈目前在使用,也很推荐的字体是 Sarasa Gothic。支持 简中/繁中/英/日 四种语言,虽然体积稍微庞大,但效果却是相当不错。 Windows 字体预览 这里也推荐作为编程字体,毕竟程序中同时存在中英文,而一个同时支持中英文的等宽字体实在难得。设置网页默认字体安装完了字体,然而 Chrome 默认并不会使用它,我们还需要 Stylus 进行指定。 添加一个新的样式,内容只需要设置所有元素使用的字体为 Sarasa Mono CL /* 全局字体设置 */* { font-family: 'Sarasa Mono CL';}/* 强制指定 input 框中的字体 */input { font-family: 'Sarasa Mono CL' !important;}这时候查看一下字体效果 夜间模式如果你像吾辈一样,喜欢暗色的主题,可以使用插件 Dark Reader,它能够让网页默认使用暗色模式,看起来和编辑器保持一致:并且,看起来很 Geek! 看起来标题栏很违和?安装一个 Dark 主题 试试看。现在,是不是变得很和谐了呢? 广告过滤目前而言,浏览网站时,没有一个广告过滤插件的话,广告的数量将是难以置信的庞大,而且讨人厌!吾辈目前在 Chrome 上仅推荐 uBlock Origin,开源免费,不推荐 Adblock Plus 与 Ublock。前者将广告拦截做成了生意(参见 向来以屏蔽互联网广告为己任的 AdBlock Plus,为什么卖起广告了?),后者则是接手开发者的自私接受捐款导致原作者 Fork 并开发了新版本 Ublock Origin(参见 Wiki uBlock Origin 历史)。 ...

June 1, 2019 · 2 min · jiezi

Chrome浏览器插件推荐

Chrome改变了我的浏览方式在我日常开发以及娱乐生活中,浏览器是我使用频率较高的一个应用,当我大学拥有第一部电脑开始,之后不论电脑换成什么,以及使用的是什么系统,我的首选浏览器都是Chrome,不仅仅是因为其速度快,更多是它丰富的扩展在吸引我 基础必备插件网页中最让人无法忍受的自然是广告,因此AdBlock总是第一个出现在我的安装列表里面 不知道诸位有没有产生过对网站进行定制的需求,如果有的话或许你可以了解一下油猴—— tampermonkey 此插件的强大之处在于可以通过安装各类脚本对网站进行定制,油猴默认是没有安装任何脚本的,你可以在 Greasy Fork 寻找自己想要的脚本,比如: 略过百度文件下载限制,百度网盘直链下载助手去掉视频播放广告,一键VIP视频解析、去广告(全网)去掉csdn恶心的下拉, csdn更多功能,可以自行发掘,这将是另外一片天地 我还有一个必备的插件就是管理插件的插件,是不是很绕哈,Extension Manager,当你插件过多的时候,就需要对插件进行管理,这款插件正好解决了我的痛点: 关于阅读浏览器对于我来说,自然是用来看得比较多,下面我将介绍几个这方面的插件 网页上各种文章的阅读体验参差不齐,也没有一款插件能够给我们带来优雅的阅读体验,答案是有的,简阅 做到了,它给你提供聚焦模式和阅读模式,具体如下: 现在知识管理插件也层出不穷,比如大名鼎鼎的 Save to Pocket ,这个插件可以将你在互联网上喜欢的一篇文章放进你的pocket,然后不论何时何地,哪怕挤公交上厕所,你可以掏出手机,在app上或者网页上访问你口袋里的知识 类似的还有有道云笔记插件 如果你是谷歌邮箱的用户,那么这款名为 Checker Plus for Gmail™ 的插件适合你,它可以多账号管理并提供邮件通知、快捷回复等功能: 如果你在工作中需要经常接触英文资料,那么这块我也有两款插件介绍给你: 第一个是达达划词翻译插件,这款插件自带生词簿及吐司弹词记忆,可与有道、扇贝单词同步,颜值也不错: 第二个是彩云翻译 (个人觉得彩云翻译的翻译质量真心不错),这款插件可以直接将整文翻译,效果如下: 怎么样,效果还不错吧,继续结合前面的tampermonkey油猴脚本,可操作空间就更大了 辅助插件如果你有图片下载的需求,可以考虑下载Image Downloader,分分钟将图片打包搞定 qq、网易云、虾米在音乐这一领域的版权上可谓三分天下,而listen1这个开源插件解决了这个问题,以后听歌不用一个一个播放器跳了 listen1 one for all free music in chinaqq、网易云、虾米,他们终于在一起了… 不过有点遗憾的是该项目可能于今年停止 歌听完了,我还想下载怎么解,别怕,还有Sound Pirate,这个插件用来下载歌曲可真是6得飞起,使用很简单,安装好,当听歌的时候它的下载标识就会默默地出现。 如果你是Markdown玩家,可能会烦恼于一些网站无法提供相关文档上的编写支持,于是这款插件Markdown Here产生了 关于开发我是一个低级无趣味的码农,现在也要开始介绍几个高级且有趣的插件了,开始 Github是我等程序员经常上的网站,这里我介绍三个插件: 第一个,将你的代码提交次数立体化,很好玩,插件名字是 Isometric Contributions 第二个,当你在线浏览代码的时候, Octotree 可以为你提供良好的阅读以及导航体验,下载文件也是一绝啊,效果如下: ...

May 29, 2019 · 1 min · jiezi

Tshare校园资源共享平台网站开发二之主机浏览器访问虚拟机apache

上一篇博客地址:Tshare校园资源分享平台(网站开发一之环境搭建) 回顾上一篇博客我们已经在一个虚拟机上搭建好了apache+mysql+php的环境,并且在虚拟机的浏览器中成功的访问到了web站点中的index.php。 新内容本篇博客将会讲解如何在主机的浏览器中访问到虚拟机的apache服务,毕竟虚拟机流畅性不如主机,而且主机是Windows系统或mac os系统,可以方便地下载安装自己喜欢地浏览器(这里建议使用Chrome浏览器)。 让虚拟机和主机能够互ping前面说过,我选择的是VMware虚拟机,在VMware上实现虚拟机和主机通讯并不需要繁琐的步骤。 1.将虚拟机的网络连接模式设置为NAT模式(网络地址转换) 2.点击编辑,选择虚拟网络编辑器,点击右下角的更改设置,然后修改子网ip和子网掩码 3.将多余的网络移除,只剩下VMnet8 4.选择NAT模式(与虚拟机共享主机IP),在点击NAT设置,设置网管IP为192.168.10.2 5.将两个钩选中,然后点击DHCP设置 6.设置动态IP范围 7.打开网络适配器中的VMnet8属性 8.设置其ip地址和子网掩码 9.重启虚拟机,打开终端输入ifconfig查看虚拟机ip地址,并尝试在主机的命令行下ping这个ip 主机通过虚拟机ip访问虚拟机的apache服务centos系统的防火墙会禁止外网访问某些端口,除非让防火墙开放端口。当然seLinux也是一个让人非常头疼的东西,很多时候即使防火墙开发端口,仍然不能访问,原因就是selinux在搞鬼。所以首先我们就把selinux关闭了。 vim /etc/selinux/config#将SELINUX=enforcing改为SELINUX=disable#保存退出,重启虚拟机,开启apache服务,在主机浏览器中访问虚拟机ip 访问成功!(如果访问失败,可能是防火墙没有开启80端口,可以百度如何让防火墙开放端口的指令) 主机上连接mysql如果你的主机上下载mysql的图形操作界面(navicat for mysql),还可以在主机上远程连接虚拟机的mysql(当然前提是虚拟机开启了mysql服务) 此时连接会报错,告诉我们192.168.10.1这个ip地址无法远程连接到虚拟机数据库,需要对虚拟机数据库做一些更改 #登录mysql/var/mysql/bin/mysql -uroot -ppassword:此处输入密码mysql> use mysql;mysql> update user set host = '%' where user ='root';mysql> flush privileges;#重启mysql服务再次远程连接,即可连接到虚拟机的数据库。当然我这里直接使用了root用户登录,你可以创建一个新用户 总结虚拟机和主机能够通讯是关键,然后是绕过防火墙,就能达到我们的目的了。下一篇博客地址:Tshare校园资源分享平台(网站开发三之数据库连接)

May 28, 2019 · 1 min · jiezi

Tshare校园资源分享平台网站开发三之数据库连接

上一篇博客:Tshare校园资源分享平台(网站开发二之主机浏览器访问虚拟机apache) 新内容环境搭建、web站点访问和数据库连接是本次开发的三个最基础的前提,这篇博客之后我们将开始真正的开发之旅 php连接数据库在虚拟机上安装sublime text 3下载地址:http://www.sublimetext.com/3#复制到/mnt目录下,直接解压缩tar -jxvf sublime_text_3.tar.bz2#配置桌面快捷方式#1. 将解压缩后目录中的sublime_text.desktop复制到/usr/share/applications下#2. 修改/usr/share/applications/sublime_text.desktop#3. 将快捷方式复制到桌面,双击即可打开sublime编辑器cp /mnt/sublime_text_3/sublime_text.desktop /usr/share/applicationsvim /usr/share/applications/sublime_text.desktop#将Exec修改为/mnt/sublime_text_3/sublime_text#将icom修改为/mnt/sublime_text_3/Icon/48x48/sublime-text.png#保存退出 主机连接上虚拟机的数据库,并创建一个新的测试数据库test 编写Db.php连接数据库,编写test.php操作数据库Db.php<?php/** * 专门用来操作数据库的类,继承mysqli类 */class Db extends mysqli{ public function __construct() { $host = "192.168.10.31"; // 数据库的主机名称,此处也就是我们虚拟机的ip地址 $user = "root"; // 数据库用户名,我们使用root用户连接 $password = "fuhao520999"; // root用户的密码,在安装mysql时我们修改过 $dbname = "test"; // 连接的目标数据库名,为我们刚才创建的test数据库 parent::__construct($host, $user, $password, $dbname); }}?>test.php<?phpinclude_once("Db.php");$db = new Db();var_dump($db);?>主机浏览器访问 此时我们成功的在php中连接上数据库了。有一个我没想到的是,竟然不需要我配置mysqli的扩展,可能是之前编译安装php的时候已经把mysqli扩展安装了。 总结本次博客内容虽然不多,但是却很重要,如果有的朋友遇到了缺少mysqli扩展的错误,可以参考以下链接:http://www.jquerycn.cn/blog/p...当然我们不需要重新下载php的源代码,因为之前我们已经下载过了,直接到指定的目录找到扩展文件,编译安装即可。

May 28, 2019 · 1 min · jiezi

令人惊叹的Chrome浏览器插件

Chrome是一个简洁而又高效(高性能,高消耗)的浏览器。接下来让我吐血推荐一些常用的Chrome插件。 日常插件uBlock Origin ----- 比Adblock性能更高的广告插件。Adkill and Media Download ----- 针对视频广告过滤,并解析在线视频下载。 PS:不一定所有视频网站都适用。Selection Search ----- 强大的搜索插件,包括右键多搜索引擎,划词搜索,顶部输入搜索。划词翻译 -----支持各种翻译词典语言翻译,划词翻译。腾讯翻译君 ----- 支持各种翻译语言翻译,划词翻译。 PS:仅限QQ浏览器使用。图片搜索 (多搜索引擎以图搜图工具)View Image ----- 整合“查看图片”与“以图搜图”功能。 PS:仅限google图片。Allow Copy ----- 破解网页无法复制。 PS:Chrome禁用js脚本也可以复制文本。Office Editing for Docs, Sheets & Slides ----- 无需安装office也可以在Chrome打开office文件。Distill Web Monitor ----- 免费监控网页内容变化工具。Click&Clean ----- 管理浏览器隐私工具。Grammarly ----- 英语拼写神器。APK Downloader ----- google play外部下载APK文件。Tampermonkey ----- 极客必备插件,随意加载第三方js与jquery。 PS:Tampermonkey常用脚本 1. `百度网盘直接下载助手` 2. `护眼脚本`编程插件page-ruler ----- 测量网页的标尺。Dimensions ----- 测量网页一些元素大小位置,类似于markman软件。Visual Event ----- 查看dom元素事件。BuiltWith Technology Profiler ----- 嗅探网站运用到的技术。wappalyzer ----- 另一个嗅探网站运用到的技术,会嗅探出编程语言。User-Agent Switcher for Chrome ----- 调试移动设备使用的标识,精准网页的渲染模式。Show CSS ----- 悬停查看css代码,可复制。Magic CSS ----- 在线编辑css代码,选择元素进行编写css/less/sass。Sourcegraph ----- github项目源码视图,支持代码定义跟踪,支持私有项目。Octotree ----- github项目源码目录结构。GitZip for github ----- github项目源码目录下载。 ...

May 26, 2019 · 1 min · jiezi

端到端测试神器Cypress进阶

前言官方文档:https://docs.cypress.io 目前只支持英文,好处是官方入门视频很多,对于英文水平不好的也很容易入手; 优缺点优点: 只要你学好js语法上应该不是很大问题获取dom类似jq,对前端同学来说是好处;缺点: 内置的GUI工具集成了谷歌内核,决定你只能是在谷歌浏览器上测试,但随着新版的Edge内核采用Chromium内核,这点缺点无伤大雅;为什么要用cypress请看:https://segmentfault.com/a/11... 看1,2,3点就可以; 入门废话不多说看了以上几点决定要不要入坑应该心里有数了; 安装网上绝大部分说采用npm i cypress -d 痛点在于内置了谷歌内核太大,每个项目都要安装太麻烦了,不便于管理,此处我们采用全局安装npm i -g cypress,既节约了磁盘空间又节约时间启动既然已经全局安装cypress的环境变量会配置到npm的环境变量中,npm的环境边练自然就在系统变量里面,cmd中输入cypress open 全局情况下打开就是慢点 直接拖入项目 点击进入项目,第一次回

May 25, 2019 · 1 min · jiezi

那些你可能不知道的浏览器奇技淫巧

平常工作少不了用浏览器,以下分享一些浏览器的使用技巧,更好的有助于你的工作。 ps: 以下技巧均在 Chrome 浏览器下测试的。 网页长截图按 F12 弹出控制台,按 ctrl+shift+p 弹出输入框输入full,选择 capture full size screenshot 然后点击就会对当前网页进图并生成下载一个图片。这个比用 QQ 截图好用的地方就是有滚动条的网页也可以全部截图到,所以叫长截图。 浏览器秒变编辑器浏览器地址栏中输入 data:text/html, <html contenteditable>回车直接变编辑器,这里可以直接输入字符进行编辑了。 编辑网页打开网站,地址栏输入 javascript:void(document.body.contentEditable='true'); 当然也可以直接在控制台输入 document.body.contentEditable=true或document.designMode = "on" 然后就可以随心所欲的改变网页内容了,所以一些网页截图不可信,比如之前有人借用王思聪名义用微博发支付宝的红包,可谓套路满满。 突破禁止复制有些网站是复制不了内容的,比如b站 的文章https://www.bilibili.com/read/cv2444771?from=category_0 ,这个时候就需要用上控制台了(按F12打开)。点击左上角箭头,选择网页内容,可以在控制台看到内容,直接复制就行了。 多账号登录平常一个浏览器只能登录一个账号,如果要登2个账号,就需要使用多个浏览器,如果只有一个浏览器怎么办,使用隐身模式(按ctrl+shift+n进入),然后登录另外一个账号。 下载网页图片想下载网页上的图片,如果一张一张的另存为,那得费不少体力,这个时候就需要控制台了。比如经常逛知乎可以看到不少妹子自拍,比如这个问题 打开控制台执行这个 copy($$('img').map(function(item){return item.src}).join("rn"))或者[...$$("img")].map(a => a.src).join('rn')就可以将所有图片地址复制好了。复制所有链接使用copy($$('a').map(function(item){return item.href;})) 然后把这些地址放在一个文件url.txt内。 接下来用wget一键下载。wget -i url.txt -P ./zhihu 所有图片都下载到本地目录zhihu了。 另外关于知乎还有个隐藏技能,按?可以打开快捷键帮助,不用鼠标也可以玩知乎了,微博也有这功能。 显示保存密码通过审查元素将type=password 的password删掉即可。 公众号:苏生不惑 点击阅读公众号原文

May 22, 2019 · 1 min · jiezi

从Google-V8引擎剖析Promise实现

从Google V8引擎剖析Promise实现 本文阅读的源码为Google V8 Engine v3.29.45,此版本的promise实现为js版本,在后续版本Google继续对其实现进行了处理。引入了es6语法等,在7.X版本迭代后,逐渐迭代成了C版本实现。 贴上源码地址:https://chromium.googlesource... 大家自觉传送。 代码中所有类似%functionName的函数均是C语言实现的运行时函数。 Define variables首先定义了将要在JS作用域使用了一些变量,提高了编译器的效率。 var IsPromise;var PromiseCreate;var PromiseResolve;var PromiseReject;var PromiseChain;var PromiseCatch;var PromiseThen;var PromiseHasRejectHandler;随后定义了一些全局私有变量供给和C语音交互,用于维护Promise的状态和进行Debug。 var promiseStatus = GLOBAL_PRIVATE("Promise#status");var promiseValue = GLOBAL_PRIVATE("Promise#value");var promiseOnResolve = GLOBAL_PRIVATE("Promise#onResolve");var promiseOnReject = GLOBAL_PRIVATE("Promise#onReject");var promiseRaw = GLOBAL_PRIVATE("Promise#raw");var promiseDebug = GLOBAL_PRIVATE("Promise#debug");var lastMicrotaskId = 0;其中GLOBAL_PRIVATE是python进行实现的,运用python的宏定义(macro)来定义调用了C语言的CreateGlobalPrivateOwnSymbol方法。 macro GLOBAL_PRIVATE(name) = (%CreateGlobalPrivateOwnSymbol(name));随后运用了一个自执行的匿名函数进行闭包逻辑。 (function() { // 主逻辑})();在闭包逻辑的最后,在promise原型上挂载了三个方法:chain,then,catch。在promise对象上挂载了all,race等六个方法。将Promise对象注册到了global。 %AddNamedProperty(global, 'Promise', $Promise, DONT_ENUM);InstallFunctions($Promise, DONT_ENUM, [ "defer", PromiseDeferred, "accept", PromiseResolved, "reject", PromiseRejected, "all", PromiseAll, "race", PromiseOne, "resolve", PromiseCast]);InstallFunctions($Promise.prototype, DONT_ENUM, [ "chain", PromiseChain, "then", PromiseThen, "catch", PromiseCatch]);Start from constructorvar $Promise = function Promise(resolver) { // 如果传入参数为全局promiseRaw变量的时候return if (resolver === promiseRaw) return; // 如果当前函数不是构造函数的化,抛出错误这不是一个promise if (!%_IsConstructCall()) throw MakeTypeError('not_a_promise', [this]); // 如果传入参数不是一个函数的话,抛出错误,传入参数不是一个function if (!IS_SPEC_FUNCTION(resolver)) throw MakeTypeError('resolver_not_a_function', [resolver]); var promise = PromiseInit(this); try { // debug相关忽略 %DebugPushPromise(promise); resolver(function(x) { PromiseResolve(promise, x) }, function(r) { PromiseReject(promise, r) }); } catch (e) { // 报错之后走到错误处理函数 PromiseReject(promise, e); } finally { // debug相关忽略 %DebugPopPromise(); }}构造函数在做完额外的异常和参数判断后,进入主逻辑调用PromiseInit方法初始化promise,随后调用了resolver方法,传入了两个默认的处理函数。在promise在内部被调用时(PromiseDeferred方法被调用时)会实例化$promise,将默认方法return回去,使得创建的promise示例具有resolve和reject方法。 ...

May 22, 2019 · 4 min · jiezi

爬虫再现之妹子图全站爬取之初级版本

序#### 做了好久的爬虫+少量web,突然开始专门做 web 开发稍微有点不太适应,毕竟比起来爬虫相对还是稍稍有点无聊的,但是又不想荒废了自己的爬虫,就准备写点关于爬虫的东西,把以前用过的东西都再过一边,毕竟感觉爬虫跟 web 没有太大的区别,并发,缓存,分布式,消息队列......言归正传 之所以爬取妹子图,一是因为简单方便,比较适合做项目展示,写博客不就是为了展示么?目前就是准备先完整的爬取,再并发(多进程+多线程 or 多线程+协程(asyncio)), 全站爬取(深度优先 or 广度优先), 数据解析(清洗?), 数据去重(redis), 数据储存(MongoDB, Mysql, csv, excel), 定时更新(crontab), 增量爬取....再三声明:本次爬取,会分别使用 requests + scrapy 爬取, 并稍微有点深度的解析 scrapy 框架使用, 并带领喜欢爬虫,以及想要学习爬虫的同学缓缓深入, 爬虫的天堂!在本连载连载期间, 会分别对这些爬虫中所要使用的类库以及工具的重要部分做专门的实例讲解,并单独开一篇文章专门讲解!别急别急,慢慢来。。。。开发环境: win10, Python3.6, fidder, Pycharm开发主要工具库: Requests, BeautifulSoup, Xpath, re, scrapy1. 爬取妹子第一步:浏览并分析目标网站结构目的: 搜索目标数据所在,分析网站结构,设定合理的爬取方案,这块主要是确定行动方案,其他的后面再说。- 进入该网站首页, 看到该网站总共有 8 个大分类, 也就是说我们爬取的数据主要就是这么几个大的分类,首页跟每日更新可以自动过滤.毕竟我们后面也是需要分类的,首页跟每日更新,没有明确的确定分类, 也就是说我们只需要在意中间 6 个即可.如下图所示: 再往下看,会发现在这 6 个分类里面, 都有总页数,可以确定每个分类需要获取的总页数, 并且发现街拍跟自拍这两项跟其他的分类不一样, 这两个直接每个大分类下面都是完整的照片, 而另外四个分类下面, 是有若干个小标题, 也就是说, 这两个分类没有下一层; 接下来点击剩下的四个分类的任意小标题进入, 发现我们要的图片, 就在这里啊!哇咔咔..... 在这里你会发现,这每个标题就是一个组图,这个下面的总页数就是每个组图的照片数量;也就是说图片的链接就是在这个页面获取到的,这就是我们获取图片的地方; 至此,网页结构分析完毕。总结:爬虫大致的过程就是 首页—>获取到分类链接->循环分类->获取每个分类的总页数->循环总页数->获取每个页面的组图主题以及每个组图的总页数->获取图片2.爬取妹子第二步:分析网站 url 结构 跟 请求- 一般网页请求都是 http,https 请求, 抓包工具最合适的是 fidder , 谁要是说花瓶的话,我肯定要喷他的,要是说大鲨鱼,我也会喷他,毕竟他们都不够合适啊;当然, chrome 的 f12 也是抓包分析的利器, F12 适合简单的分析,分析下简单的 url 结构还是可以的, 一般的网站 F12 即可快速搞定;- fidder 抓包原理: fidder 启动后建立一个本地代理服务器,类似 vpn ,默认监听127.0.0.1:8888, 拦截并转发请求;- 关于 fiddler 的抓包方法,以及配置使用什么的, 由于本人太懒,就不打算描述了,看家尽可 百度谷歌必应, 一大把的教程; so easy....目的:拼接所要循环的 url , 分析请求以及反爬抓包分析 url 结构:点击查看分类的第二页, 如下图所示, 可以简单的分析出分类的翻页链接,可以照此拼接出来, 而且页数的数字换成1之后,页面会跳转至分类首页,而不是带页数的链接,但是无论跳不跳转,网页的数据不变,都不影响我们的数据获取; ...

May 21, 2019 · 1 min · jiezi

Entity-Framework初体验

零、初体验新建控制台程序,名称为:MyFirstEF在NuGet中搜索 Entity Framework,如下图: 创建 Blog 类:public class Blog{ public int Id { get; set; } public string Name { get; set; } public string Url { get; set; } public DateTime? CreatedTime { get; set; } public double Double { get; set; } public float Float { get; set; }}创建一个继承自EF上下文的类,此上下文是与数据库交互的一个中间桥梁,我们可以称之为会话,并且为每一个模型公开一个DbSet:public class EfDbContext : DbContext{ public EfDbContext() { } public DbSet<Blog> Blogs { get; set; }}注:上下文派生类中定义DbSet有如下三种方式: //用DbSet属性public class EfDbContext : DbContext{ public EfDbContext() { } public DbSet<Blog> Blogs { get; set; }}//用IDbSet属性public class EfDbContext : DbContext{ public IDbSet<Blog> Blogs { get; set; }}//只读属性public class EfDbContext : DbContext{ public DbSet<Blog> Blogs { get {return Set<Blog>();} }}在主函数上添加如下代码:static void Main(string[] args){ using (var efDbContext = new EfDbContext()) { efDbContext.Blogs.Add(new Blog() { Name = "张三", Url = "http://www.baidu.com" }); efDbContext.SaveChanges(); }}运行控制台程序,如果未出现任何报错,则会在VS对应的本地数据库中看到新创建的 Blogs 表和一条新数据。 ...

May 14, 2019 · 1 min · jiezi

如何更好的使用bug管理工具MadPecker场景篇

Hi,大家好,我是MadPecker,一款免费,好用的缺陷(Bug)管理SaaS软件 今天,我给大家介绍一下在项目开发过程中可能遇到的几个场景! 网址:www.madpecker.com 场景一“小啄,首页的UI样式帮我改一下。”“小啄,你那个接口写好了没有啊?”“小啄,刚刚和你说的那个BUG改得怎么样了?” ...... ......“老大,你刚刚叫我改什么来着?”我们都知道,在项目进行的过程中一定会出现形形色色的问题。显然,口头表述并不是一种好的问题解决方式。如果把各种问题全部堆积在聊天工具上,开发人员不停地上翻聊天记录也不是个办法。MadPecker的任务管理工具把所有的任务归类好,展示在任务列表上,不管是BUG、测试、开发、还是需求,任务创建者只需要把这个任务指派给项目中的某个成员,这个处理人就能收到提醒并及时处理任务。 上传图片时,MadPecker支持点击上传、拖拽上传和粘贴上传。 提交BUG页 BUG详情页场景二“小啄,我注册登录的模块已经开发好了,你帮我测一下呗。”“行!”......“咦,小啄,你是不是没写测试用例啊,这个功能你好像漏测了呢!” 测试漏项、测试不规范等问题一直困扰着测试工作者。MadPecker中的测试管理共分为测试用例、测试场景、测试执行三个部分,测试人员可以根据场景录入测试用例,也可以在录入测试用例的时候关联测试场景,并且用例可以复用,进一步减少了测试人员的工作量。在测试执行中,对一个场景测试不通过,测试人员可以直接提交BUG给开发人员。MadPecker完成了测试人员与开发人员之间的互动,把整个测试流程变得紧凑起来。 提交测试用例页 测试场景列表页 测试执行操作页场景三“在XX应用商店发布应用太慢了吧!”没错,对于很多急于上线的用户来说,大部分应用商店的上传机制经常会让应用上传之后还要经过漫长的时间才能将应用推向大众。MadPecker支持应用随时上传随时下载,上传应用之后,系统自动生成二维码,方便用户下载。并且MadPecker支持合并应用功能,不同平台的应用可以合并成同个二维码,所以不同平台的手机都可以扫描同个二维码下载应用了。 下载应用界面 以上为本期全部内容,如果您想要了解更多关于MadPecker的使用或者您想要了解我们的平台其他功能更新,欢迎您到我们的帮助中心查看。同时,如果您对我们的平台有哪些疑惑或建议,欢迎您到我们的用户社区/官方QQ群/微信群畅所欲言。

May 13, 2019 · 1 min · jiezi

Chrome-74-带来的新功能

What’s new in Chrome 74翻译:疯狂的技术宅https://blog.logrocket.com/wh...本文首发微信公众号:前端先锋欢迎关注,每天都给你推送新鲜的前端技术文章 Chrome 74 已经发布了,虽然从用户的角度来看并没有什么令人兴奋的东西,但是对开发人员来说带来了一些好处。新版本附带了新的 Javascript 私有类字段、允许用户减少动画的媒体查询和 Windows 的深色模式等等。 公共类字段,私有类字段你可能还记得,Chrome 72 在1月份增加了对 Javascript 公共类字段语法的支持。这是一种简化语法的新方法,它允许直接在类定义中定义类字段,且不需要构造函数。 现在在 Chrome 74 中加入私有类字段,它与公有类字段的功能大致相同,但是用 # 来表示它们是私有而不是公共的,当然它们只能在类的内部访问。 先复习一下公共类字段,如下所示: class IncreasingCounter { // Public class field _publicValue = 0; get value() { return this._publicValue; } increment() { this._publicValue++; }}私有类字段添加了 #: class IncreasingCounter { // Private class field #privateValue = 0; get value() { return this.#privateValue; } increment() { this.#privateValue++; }}不那么快事实证明,有些人并不是那么喜欢现代网站上的华丽动画。实际上视差滚动、缩放和跳跃动作效果会使一些动画出问题,这并不好玩。操作系统已添加了减少这类动作的选项,在 Chrome 74 上你可以通过使用媒体查询,来减少动画中的动作。 ...

May 12, 2019 · 1 min · jiezi

浏览器元素尺寸与位置查询指南

前言这篇文章主要介绍了有关浏览器中获取坐标以及尺寸的几种途径,算是比较全的一篇文章了. 在浏览器中获取元素的坐标以及尺寸是非常容易的,有非常多种方式来完成这些需求,但是杂乱的API和很多兼容处理导致了浏览器中没有直接的方式来获取我们想要的结果. 仔细想想这个问题,为什么浏览器并没有直接提供一个简单的属性就告诉你浏览器窗口的大小,或者一个元素的宽高. 就拿div元素来举例,我们有很多的问题影响到了元素宽高: border 是否纳入宽高的计算?padding 是否纳入宽高的计算?magin 是否纳入宽高的计算?box-sizing:border-box; 时候该如何计算?父元素使用了overflow:hidden;把我们的元素裁剪了,这时候的宽高该如何计算?元素使用了overflow出现了滚动条此时该如何计算?而如果要获取一个浏览器窗口的大小,你还要面对我们到底是要获取哪个大小? 屏幕大小?浏览窗口大小?浏览区域大小?是否包含滚动条?当然最终你还要面临一个兼容问题,致我们敬爱的IE浏览器,不过本文可不探讨浏览器之间的差异.不过本文的涉及到的内容应该在IE9以上都是可以正常使用的(不过建议你还是查下can i use 或者MDN). 浏览器部分浏览器的宽高计算主要通过window对象来完成. 这个对象上提供了几个关键属性: window.innerWidthwindow.innerHeightwindow.outerWidthwindow.outerHeight用人类语言来描述这几个属性就是. 属性名称人类解释innerWidth获取页面可视区域的宽度包括右侧的滚动条(如果有的话).所谓的可视区域就是HTML页面的内容区域不包括浏览器自身的ui所占用的空间(地址栏和菜单栏等).innerHeight获取页面可视区域的高度包括底部的滚动条(如果有的话).解释同上.outerWidth获取浏览器窗口宽度.outerHeight获取浏览器窗口高度.友情出演windows画图: 注意:单位均为px. 注意:滚动条并不视为浏览器的ui中的内容,而是视为内容区域的一部分,右侧默认的滚动条的宽度包含在window.innerWidth中,但是不属于html元素和html下的任何元素. 元素部分属性属性名称人类解释element.clientWidth元素内容区域宽度+padding的宽度,如果宽度溢出且裁剪那么不包含被裁剪掉的部分.element.scrollWidth当子元素宽度溢出,这里提供的是子元素的宽度包括溢出的部分,大小计算和clientWidth一样.element.offsetWidth相当于计算边框宽度的clientWidth,宽度计算为content+padding+border.element.clientHeight元素内容区域高度+padding的高度,如果高度溢出且裁剪那么不包含被裁剪掉的部分.element.scrollHeight当子元素高度溢出,这里提供的是子元素的高度包括溢出的部分,大小计算和clientHeight一样.element.offsetHeight相当于计算边框高度的clientHeight,高度计算为content+padding+border.element.clientLeft元素左边框的宽度element.scrollLeft计算较为复杂,看后续详解element.offsetLeft计算比较复杂,看下面详解element.clientTop元素上边框的宽度element.scrollTop计算较为复杂,看后续详解element.offsetTop计算比较复杂,看下面详解滚动条的规律无论是横向滚动条还是纵向滚动条,对于测量clientXXX这个单位来说是不包括滚动条的宽(高)的. 例如在下面这张图中我们进行测量父元素(黑色区域)的clientWidth结果和子元素(红色区域)的clientWidth的大小是一样的. 不过需要注意的是,一旦出现了滚动条对于clientWidth来说就意味着宽度减小(高度同理). 注意:图片所指的宽度是clientWidth API名称是否包含滚动条大小offsetXXX包含clientXXX不包含scrollXXX不包含所以在margin:0;padding:0;border-width:0;情况下offsetWidth - clientWidth=滚动条的宽度. 通过这种方式我求出了chrome浏览器滚动条大小是17px整,但是不要忘记这些API只会返回整数. 注意:scrollXXX对于滚动条计算的规则和clientXXX表现一致. 含有box-sizing:border-box的计算请记住,对于clientXXX来说,元素的大小就是padding+content. 而使用border-box后元素的表现就是padding和border的修改就不会影响到元素的大小. 此时width是多少clientWidth就是多少,height同理. 但是不要忘记了边框不参与clientXXX的计算,所以border的修改并不会影响元素的宽高变化,那么那么当border变大,对应的clientXXX就变小. 一个元素设置了border-box: box{ width:100px; padding:20px; border:20px solid; box-sizing:border-box;}此时clientWidth= 100px - 20px*2(左右边框的宽度) = 60px 由于offsetXXX的计算是包含border的大小的,所以如果一个元素设置了border-box那么offsetWidth就等于元素的width大小,因为border被限制到了width中. offsetTop和offsetLeft子元素的offsetWidth|height是相对于父元素内容区域(padding+content)左侧和顶部的偏移量. 这个两个是相对值,是要求出向对于父级使用定位情况下来进行计算的,这个父元素可以通过HTMLElement.offsetParent来获取到. 例如:父级使用absolute或者relative. 注意:后文提出的父元素都指的是使用了相对定位的父元素. 注意:以上都是对于块级元素所描述的,对于行内元素或者td等元素相对的父元素不尽相同,这里不考虑这些情况,详情可以查看上方的链接. 情况1 在子元素使用了绝对定位的情况下,父元素无法干预子元素,所以子元素的scrollLeft就是left+margin-left. 情况2 第二种情况就是父元素和子元素都使用了相对定位,而相对定位是不脱离文档流的,那么父元素的padding-left就会影响到子元素的scrollLeft属性. 在线实例 注意:貌似offsetTop和Left在不同浏览器下有不同计算值,会带来兼容性问题,这里就不展开了,有兴趣的读者可以去查阅相关资料. scrollTop和scrollLeft首先scrollTop和scrollLeft是一对可读写的属性,这意味着你可以获取他的值也可以设置它从而控制滚动的距离. 注意:scrollTop|scrollLeft是用在含有滚动区域的元素上(图中黑色边框的元素),而不是被滚动的元素上测量,被滚动的元素scrollTop永远是0. 简单理解:在垂直方向上含有滚动条的元素的内容区域的顶部(padding+content)相对于自身顶部边框的底部向上移动的距离(水平方向同理). 就是scrollTop的大小(图中超出去的部分). 元素方法getBoundingClientRect关于这个方法建议阅读MDN的指南.当然你也可以选择听我瞎扯几句. 这个api是ie首先提出(早在ie4时候就有了)的这也是ie对web开发的贡献之一. 调用这个api会返回一个DOMRect对象,这个对象多次易名,不过没有变化过基本概念. ...

May 12, 2019 · 1 min · jiezi

匿名函数以及闭包内部this指向函数调用模式的问题

网上看到一句话,匿名函数的执行是具有全局性的,那怎么具有的全局性呢?闭包内部this的指向是window,为什么指向了window呢?下面通过js函数调用模式和部分案例分析了为什么确实如此1.js函数调用的模式1.方法调用模式和函数调用模式如果一个函数被设置为一个对象的属性,则称它为一个方法。当通过对象对其进行调用时,即this的方法调用模式。在方法调用模式下,函数中的this指向该函数所属的对象。当一个函数并非对象的属性,而是直接作为函数进行调用时,为函数调用模式。此模式来调用函数的时候,this绑定的是全局对象。这是语言设计的一个错误。倘若语言设计正确,那么当内部函数被调用时,this应该仍然绑定到外部函数的this变量。这个设计错误的后果就是方法不能利用内部函数来帮助它工作,因为内部函数的this被绑定了错误的值,所以不能共享该方法对对象的访问权var obj = { val : 1, show : function(){alert(this.val);},//方法调用模式 outFunc : function(){ function innerFunc(){ console.log(this); } innerFunc(); //函数调用模式 }};obj.innerFunc();//在严格模式下,console.log(this)中的this为undefined,//否则,console.log(this)中的this为全局对象(浏览器中为window)//下文讲解为什么2.构造器调用模式当以new来调用一个函数时,即构造器模式。当使用new调用时,发生这些事情:创建一个连接到该函数prototype的新对象将this绑定到创建的新对象上函数结束时,如果没有返回其它对象,就返回this,即新创建的对象。 var quo=function(string){ this.status=string; } quo.prototype.get_status=function(){ return this.status; } var qq=new quo("aaa"); alert(qq.get_status());3.上下文调用模式(call,apply)var myobject={};var sum = function(a,b){ return a+b;};var sum2 = sum.call(myobject,10,30); //var sum2 = sum.apply(myobject,[10,30]); alert(sum2);2.闭包和匿名函数案例分析(这两种都是函数调用模式) var person = { name :'one', sayOne:function () {//方法调用模式 console.log(this.name) }, sayTwo:function () {//函数调用模式 return function () { console.log(this.name) } }, wrap: function(){//函数调用模式,匿名函数的执行环境具有全局性的由来 (function (){ console.log(this.name) })() } } person.sayOne()//one sayOne调用者是person对象,所以this指向person;(方法调用模式) person.sayTwo()()//window 返回的匿名函数在全局执行所以是window(函数调用模式) person.wrap()//window 语言就是这样设计的,也是匿名函数具有全局性的由来(函数调用模式)3.事件监听内部调用方法案例分析 var div=document.getElementById("one"); function f2(){ console.log(this) } div.onclick =function () { console.log(this)//one那个节点 f2()//window(函数调用模式) }4.综合应用:函数节流案例分析1.throttle函数的执行环境具有全局性,内部this通常是指向window的,然后返回一个匿名函数。2.返回的匿名函数绑定了事件,this指向监听的元素(document)3.fn其实与上面返回匿名函数形成了闭包,且fn也其实是一个匿名函数,匿名函数的执行具有全局性,fn内部this应该指向window4这里用apply修正this指向,使fn内部的this重新指向document ...

May 11, 2019 · 1 min · jiezi

浏览器内核

1.什么是内核,及浏览器作用浏览器的主要功能就是向服务器发出请求,在浏览器窗口中展示您选择的网络资源。这里所说的资源一般是指 HTML 文档,也可以是 PDF、图片或其他的类型。资源的位置由用户使用 URI(统一资源标示符)指定。浏览器解释并显示 HTML 文件的方式是在 HTML 和 CSS 规范中指的。这些规范由网络标准化组织 W3C(万维网联盟)进行维护。多年以来,各浏览器都没有完全遵从这些规范,同时还在开发自己独有的扩展程序,这给网络开发人员带来了严重的兼容性问题。如今,大多数的浏览器都是或多或少地遵从规范。浏览器的内核是指支持浏览器运行的最核心的程序,分为两个部分的,一是渲染引擎,另一个是JS引擎。渲染引擎在不同的浏览器中也不是都相同的。 2.主流浏览器主流浏览器是有一定市场份额且有自己独立研发内核的浏览器份额排行:https://tongji.baidu.com/data...IE/Edge,Chrome,Safari,Opera,Firefox 3.浏览器引擎列表 3.几大厂商浏览器内核简介IE/Edge:微软的IE浏览器浏览器更新至IE10后,伴随着WIN10系统的上市,迁移到了全新的浏览器Edge。除了JS引擎沿用之前IE9就开始使用的查克拉(Chakra),渲染引擎使用了新的内核EdgeHTML(本质上不是对Trident的完全推翻重建,而是在Trident基础上删除了过时的旧技术支持的代码,扩展和优化了对新的技术的支持,所以被看做是全新的内核)。Safari:Safari自2003年面世,就一直是苹果公司的产品自带的浏览器,它使用的是苹果研发和开源的Webkit引擎。Webkit引擎包含WebCore排版引擎及JavaScriptCore解析引擎,均是从KDE的KHTML及KJS引擎衍生而来。Webkit2发布于2010年,它实现了元件的抽象画,提高了元件的重复利用效率,提供了更加干净的网页渲染和更高效的渲染效率。另外,Webkit也是苹果Mac OS X系统引擎框架版本的名称,主要用于Safari、Dashboard、Mail。Chrome:提到Chrome浏览器,一般人会认为使用的Webkit内核,这种说法不完全准确。Chrome发布于2008年,使用的渲染内核是Chromium,它是fork自Webkit,但把Webkit梳理得更有条理可读性更高,效率提升明显。2013年,由于Webkit2和Chromium在沙箱设计上的冲突,谷歌联手Opera自研和发布了Blink引擎,逐步脱离了Webkit的影响。所以,可以这么认为:Chromium扩展自Webkit止于Webkit2,其后Chrome切换到了Blink引擎。另外,Chrome的JS引擎使用的V8引擎,应该算是最著名和优秀的开源JS引擎,大名鼎鼎的Node.js就是选用V8作为底层架构。Firefox:火狐的内核Gecko也是开源引擎,任何程序员都能为其提供扩展和建议。火狐的JS引擎历经SpiderMonkey、TraceMonkey到现在的JaegerMonkey。其中JaegerMonkey部分技术借鉴了V8、JSCore和Webkit,算是集思广益。Opera:Opera在2013年V12.16之前使用的是Opera Software公司开发的Presto引擎,之后连同谷歌研发和选择Blink作为Opera浏览器的排版内核。4.国内浏览器情况国内浏览器厂商(QQ、2345、搜狗、猎豹、UC、360)也有一定的市场占有率。且大多数为双核总结国内厂商内核来看,一般为三类:一、使用的Trident单核,如:2345、世界之窗;二、使用Trident+Webkit/Blink双核,如:qq、UC、猎豹、360、百度;三、使用Webkit/Blink单核,如:搜狗、遨游。 双核浏览器通过WebKit内核来访问一些不需要进行网上交易的网站,使用起来速度更快更方便;双核浏览器在进行支付系统或者是网上银行的访问时,则使用的是Trident内核。这就是双核浏览器的高速模式和兼容模式。双核浏览器是一个不仅仅具有ie浏览器内核同时兼容非ie浏览器内核的浏览器,可以让用户在浏览器当中体验不同的需求。

May 11, 2019 · 1 min · jiezi

JS匿名函数内部this指向

网上看到一句话,匿名函数的执行是具有全局性的,那怎么具有的全局性呢?this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象1.案例中,第一个say打出来的是Alan,而第二个则是window var name = 'window' var person = { name :'Alan', sayOne:function () { console.log(this.name) }, sayTwo:function () { return function () { console.log(this.name) } } } person.sayOne()//Alan person.sayTwo()() // window 2.原因函数内部的this指向调用者sayOne调用者是person对象,所以this指向person;sayTwo的调用者虽然也是person对象,但是区别在于这次调用并没有打出this而是在全局返回了一个匿名函数而这个匿名函数不是作为某个对象的方法来调用执行,是在全局执行3.我们也可以更改this指向,这里应用JS高级编程的案例var name = "global";var foo = { name: "foo", getName : function(){ console.log(this.name); }}var bar = { name: "bar", getName : function(){ return (function(){ console.log(this.name); })(); }}foo.getName(); //foofoo.getName.call(bar); //barfoo.getName.call(this); //globalfoo.getName.call(window); //global(function(){ console.log(this.name)}.bind(bar))(); //bar(function(){ console.log(this.name)}.bind())(); //global

May 10, 2019 · 1 min · jiezi

macOS-Chrome-禁用暗色背景

macOS 上 Chrome 升级至 74.0.3729.131 版本后,地址栏按照 macOS 选择的暗色主题,也变成了黑色背景样式,显得非常突兀。以下备忘上述问题的解决方案。1. 解决方案在终端中执行: defaults write com.google.Chrome NSRequiresAquaSystemAppearance -bool Yes之后重启 Chrome 即可。 采用这一方案,能够在保持 macOS 其它软件仍受主题选择影响的情况下,改变 Chrome 上的表现。 参考链接How to disable Google Chrome Dark Mode?

May 10, 2019 · 1 min · jiezi

BFC块级格式上下文详解

1.BFC简要定义BFC(Block formatting context)直译为"块级格式化上下文"。它是一个独立的渲染区域,它规定了内部如何布局,是决定块盒子的布局及浮动相互影响范围的一个区域,并且与这个区域外部毫不相干。 2.BFC创建方式根元素或其它包含它的元素;浮动 (元素的float不为none);绝对定位元素 (元素的position为absolute或fixed);行内块inline-blocks(元素的 display: inline-block);表格单元格(元素的display: table-cell,HTML表格单元格默认属性);overflow的值不为visible的元素;弹性盒 flex boxes (元素的display: flex或inline-flex)3.BFC内部特性内部的盒会在垂直方向一个接一个排列(可以看作BFC中有一个的常规流);处于同一个BFC中的元素相互影响,可能会发生margin collapse;但不同BFC可以阻止margin collapse每个元素的margin box的左边,与容器块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此;BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之亦然;计算BFC的高度时,考虑BFC所包含的所有元素,连浮动元素也参与计算;浮动盒区域不叠加到BFC上;4.BFC应用实例1.BFC清除浮动将父元素设置一个能让其变为BFC区域的属性,不如overflow:auto <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <style> #one{ background:green; width: 100px; height: 50px; float: left; } #two{ background: red; width: 200px; height: 50px; float: left; } #box{ border: 2px solid salmon; width: 400px; overflow: auto; } </style></head><body><div id="box"> <div id="one">one</div> <div id="two">two</div></div></body></html>2.BFC处理margin collapse在CSS中,两个或多个毗邻的普通流中的盒子(可能是父子元素,也可能是兄弟元素)在垂直方向上的外边距会发生叠加,这种形成的外边距称之为外边距叠加。这里讲解父子元素,兄弟元素同理。 <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <style> *{ margin: 0; padding: 0; } p{ padding: 0; margin: 20px 0 20px 0; height: 20px; background-color: burlywood; color: #fff; } div{ overflow: auto;//前后的区别取决于这句话,加上就能让父级生成BFC区域包含它们 width: 250px; background-color: #ccc; } </style></head><body><div> <p>aaaaaaaaaaaaaa</p> <p>bbbbbbbbbbbbbb</p></div></body></html>BFC改造后 ...

May 9, 2019 · 1 min · jiezi

梳理自己所写浏览器工作原理

浏览器工作原理网上有一篇已经写得很好了,浏览器工作原理。那我自己写,是为了看看自己学会多少。输入和输出还是两回事。 浏览器做了什么?浏览器解析我们在html编辑器所写的代码有html、css、js。关键HTML怎么解析为DOM、CSS解析为CSSOM、又是如何解析JavaScript的。又怎么把它们结合在一起? 浏览器到底是如何工作的?首先它长的样子,都见过比如谷歌浏览器,地址栏、工具栏、各种功能的控件、主屏展示。跟用户交互的地方不多。后退、前进、刷新、主页、地址栏、窗口页、书签这些。 我们要看到某个网站内容,只有一个输入入口,就是地址栏。在地址栏里面输入,某个网站地址,浏览器就会去处理我们输入的地址栏,解析IP地址、端口号,去访问某个服务器上的资源。 在地址栏输入一个地址,一个回车,瞬间一个网页出现在当前浏览器窗口的屏幕上。一个输入、瞬间输出这个过程做了什么事情? 计算机输入-处理-输出,都是这个过程。地址输入-浏览器处理-输出网页。 根据极客时间的winter老师所说:1 浏览器首先使用HTTP或HTTPS协议,向服务器请求页面2 请求回来的页面,也就是浏览器收到的HTML会解析成DOM树3 计算DOM树上的CSS属性,怎么计算?4 最后根据CSS属性对元素逐个进行渲染,得到内存中的位图5 一个可选的步骤是对位图进行合成,6 合成后绘制到界面上。 从HTTP请求回来后,产生流式数据,后续的DOM树构建、CSS计算、渲染、合成、绘制都是流式处理,不是说,一定等到全部HTML解析完毕成DOM、CSS计算完成后、渲染才开始、合成才开始、绘制才开始。 不是说每一个步骤的数据都要一步到位。 浏览器结构用户界面、浏览器引擎、呈现引擎、网络调用、JavaScript引擎、数据库、用户界面后端。 如何解析请求回来的HTML代码,DOM树又是如何构建的?服务端响应给我的body,如何处理,也就是HTML如何处理? 词是如何被拆分的看下面的一行HTML代码 <p class="a">text text text</p>最小标签”<p,开始标签里面有属性,不能取"<p class="a">"为最小单元,也就是词。那么class="a"是第二个词,第三个词是>,第四个词是text text text,第五个词</p> 字符流拆成词,有一套状态机去实现的拆分成词。 输入字符流,浏览器某个功能模块处理字符流,输出一个词。输入、处理、输出计算机最基本模式。

May 9, 2019 · 1 min · jiezi

DOS-Network与DUO-Network达成战略合作加速通证化加密衍生品的开发

各位亲爱的DOS Network的支持者和关注者,我们很高兴地宣布DOS网络已与DUO Network达成战略合作。双方将紧密合作,以促进和加速通证化加密衍生品的开发。 过去几年,加密市场迅速增长。然而,加密货币的迅速崛起伴随着以前未曾见过的波动性,阻碍了常规投资者和机构的进一步接受和投资,并且持续升高的价格波动已经成为现实世界采用区块链技术的主要障碍。 DUO Network团队认为,人们应该从传统金融市场中学到的是需要成熟的市场工具(如衍生品)来帮助管理波动性,增加流动性并对冲下行风险。 什么是DUO网络?DUO Network是一个去中心化的平台,可以进行通证化衍生产品的发行,交易和结算。它主要由抵押自治令牌(简称CAT),Price Oracle,DUO DEX组成。该平台旨在通过抵押智能合约和自治参考利率降低传统衍生品交易中的风险和障碍,从而创建透明和自主的衍生品市场。 DUO旨在解决当前加密市场中高波动性,流动性不足以及缺乏风险管理工具的问题。正如传统市场所见,衍生品市场的成功发展往往证明了标的资产类别的深度和成熟度。 什么是DOS网络?DOS网络一个支持多链的可扩展的去中心化预言机二层服务网络,为多个区块链网络提供实时数据传输和计算预言机解决方案。它使Dapps能够以安全有效的方式,通过链下分布式网络获取外部数据并执行复杂的计算,这将鼓励越来越多的应用场景出现在区块链上。 衍生品定价和交易的核心是对衍生品与底层证券对冲的能力,而底层证券的定价应具备一系列理想的特征 - 相关性,及时性和操纵性。但是,区块链授权的智能合约与现实中的互联网世界隔离,无法直接访问外部数据。 因此,作为DUO令牌生态系统的三个主要组成部分之一,数据传输预言机对DUO网络非常重要。DUO需要数据预言机为其提供时实时不可篡改的价位数据。 为何选择DOS网络?与其他预言机项目相比,DOS网络有 6 项主要的技术创新,使得与前面提到的理想特性完美匹配的价格数据能够以安全、可靠、高效和可扩展的方式提供给DUO Network: 网络去中心化:设计完全符合区块链思想,可以避免单点故障问题,无需信任第三方独立机构;实时可验证结果:数据结果可实时获取基本零延迟,并且通过密码学存储,可在链上验证数据正确性;完美多链兼容:轻量级链上接口,密码学共识于链下完成,可服务所有主流公链;极强的安全性:可验证的随机数引擎及加密签名技术,保证服务网络结果的可靠性;高拓展性低成本:由多节点于链下完成可靠数据获取或复杂计算,高性能却降低链上开销;正向奖励机制:服务网络中完成数据获取或计算任务的诚实节点将获得奖励激励。与DUO Network合作,DOS网络的服务范围将大大扩展。DUO Network将成为DOS网络早期的采用者之一,并将成为DOS网络数据预言机的重要客户。随着DOS网络的Beta版即将上线,DUO Network将在未来提供全面支持,甚至加入我们的DOS网络作为节点运营商。 DOS网络和DUO网络将密切合作,实现资源共享,实现合作共赢。双方将致力于通过抵押智能合约和分布式的数据预言机来降低传统衍生品交易中的风险和障碍,从而加速通证化加密衍生品的开发并促进Dapps的大规模采用。 END -如果你对DOS Network感兴趣,欢迎添加小助手(dosnetwork001)进入社区! 关于DOS NetworkDOS Network 是一个实现了去中心化预言机的可扩展的二层网络,为主流区块链提供数据上链服务和计算力。它将区块链智能合约与真实世界的数据和事件连接起来,还为区块链提供可验证的计算能力,从而使更多应用场景能够在区块链上实现。可支持各种主流区块链,如 Ethereum、EOS、TRON、ThunderCore、Ultrain、QuarkChain 等。 官方网站:https://dos.network/中文电报群:https://t.me/dosnetwork_cn英文电报群:https://t.me/dosnetwork_enTwitter:https://twitter.com/DOSNetworkMedium:https://medium.com/@dosnetworkGithub:https://github.com/DOSNetwork

May 9, 2019 · 1 min · jiezi

CSS3动画简单案例

1.简易加载中 @keyframes myfirst { from{transform: rotate(0deg)}to{transform: rotate(360deg)} } .loading{ animation: myfirst 1.5s infinite linear;//infinite控制执行次数这里一直执行,linear执行速度,匀速 border: 16px solid #f3f3f3; border-radius: 50%; border-top:16px solid blue; width: 120px; height: 120px; } <div class="loading"></div>2.简易进度条.move { width: 0px; height: 10px; animation: moveHover 5s infinite linear; } <div class="move"></div>3.过渡属性 .change { transition: width 2s; font-size: 10px; width: 100px; height: 20px; background: yellow; -moz-transition: width 2s; /* Firefox 4 */ -webkit-transition: width 2s; /* Safari 和 Chrome */ -o-transition: width 2s; /* Opera */ } .change:hover { width: 500px; } <div class="change">鼠标滑过</div> .bigger{ font-size: 20px; width: 0; height: 0;//scale根据宽高变大,必须设置width和height background: #2A9F00; transition: transform 5s; } .bigger:hover{ transform: scale(10); } <div class="bigger">大</div>

May 8, 2019 · 1 min · jiezi

5算术逻辑单元ALU

1、ALUALU 就是计算机里负责运算的组件, 用于有意义的处理数字,比如把两个数字相加。基本其他所有部件都用到了它。ALU 有 2 个单元,1 个算术单元和 1 个逻辑单元。 2、第一个ALU英特尔 74181,发布于1970 年,是第一个封装在单个芯片内的完整 ALU。 3、制作算术单元"算术单元",它负责计算机里的所有数字操作,比如加减法,增量运算(给某个数字+1)。 原料: AND,OR,NOT 和 XOR 逻辑门。 目的:最简单的加法电路, 例如: 2 个 bit 加在一起(bit 是 0 或 1) 思路:有 2 个输入:A 和 B; 1 个输出:A、B两个数字的和。 (注意的是:A, B, 输出,这3个都是单个 Bit ( 0 或 1 )) 输入只有四种可能:(1)前三种可能是: 0 + 0 = 0 , 1 + 0 = 1 , 0 + 1 = 1。特点:这三种的输入和输出,和 XOR 门的逻辑完全一样,所以可以把 XOR 用作 1 位加法器(adder)。实现:XOR门 ...

May 5, 2019 · 1 min · jiezi

计算机科学基础8-计算机网络

计算机网络局域网 Local Area Networks - LAN媒体访问控制地址 Media Access Control address - MAC载波侦听多路访问 Carrier Sense Multiple Access - CSMA指数退避 Exponential Backoff冲突域 Collsion Domain电路交换 Circuit Switching报文交换 Message Switching分组交换 Packet Switching用户在全球网络中发送和接收信息的能力。150年前,发一封信件从伦敦到加州,要花2~3周,而且还是特快邮件。如今,电子邮件只要几分之一秒,“时延”改善了上百万倍(时延指传播一条信息所需要的时间),帮助现代世界在遍布全球的光纤中快速发展。可能觉得计算机和网络密切相关,但事实上,1970年之前,大多数计算机是独立运行的,然而,因为大型计算机开始随处可见,廉价机器开始出现在书桌上。分享数据和资源渐渐变得有用起来,首个计算机网络就出现了。 局域网第一个计算机网络出现在1950~1960年代,通常在公司或研究室内部使用,为了方便信息交换。比把纸卡或磁带送到另一栋楼里更快速可靠,这叫“球鞋网络”,第二个好处是能共享物理资源。例如,与其每台电脑配一台打印机,可以共享一台联网的打印机,早期网络也会共享存储空间,因为每台电脑的配存储太贵了。计算机近距离构成的小型网络,叫局域网,简称LAN。局域网能小到是同一个房间里的两台机器或大到校园里上千台机器,尽管开发和部署了很多不同LAN技术,其中最著名和成功的是“以太网”,开发于1970年代,在施乐的“帕洛阿尔托研究中心”诞生,今日仍被广泛使用。 以太网的最简单形式是:一条以太网电线连接数台计算机。当一台计算机要传数据给另一台计算机时,它以电信号形式,将数据传入电缆,当然,因为电缆是共享的,连在同一个网络里的其它计算机也看得到数据。但不知道数据是它们的,还是给其他计算机的,为了解决这个问题,以太网需要每台计算机有唯一的媒体访问控制地址,简称 MAC地址。 这个唯一的地址放在头部,作为数据的前缀发送到网络中,所以,计算机只需要监听以太网电缆,只有看到自己的MAC地址,才处理数据。这运作的很好,现在制造的每台计算机都自带了唯一的MAC地址,用于以太网和无线网络。 多台电脑共享一个传输媒介,这种方法叫“载波侦听多路访问” 简称“CSMA“,载体指运输数据的共享媒介。以太网的“载体”是铜线,WiFi的”载体“是传播无限电波的空气,很多计算机同时侦听载体,所以叫“侦听”和“多路访问”。

May 5, 2019 · 1 min · jiezi

chrome插件

1、editthiscookie 编辑cookie的插件 editthiscookie下载地址安装使用教程 谷歌浏览器中安装.crx 插件若是无法安装打开 chrome://extensions/ 在安装 安装包失效的解决方法 1、crx后缀修改为zip 2、unzip xxx.zip -d 指定空文件夹附安装包失效详细教程-转载附 zip常用命令

April 30, 2019 · 1 min · jiezi

我是如何用Madpecker去管理bug的

现在国内外的bug工具很多,今天我要说的是我们团队现在用的一款功能强大操作方便的bug管理工具---MadPecker,我们平时提BUG、做测试、敏捷开发什么的都是用的这个。 1.登录他们的官网 https://www.madpecker.com/home2.注册一个账号,这个工具是完全免费的,这一点是很良心的 3.接着就可以进入MadPecker工具平台了 4.首先创建一个项目,并给项目一个名称 5.为项目添加所需工具(敏捷面板真的不错) 6.添加项目成员 7.bug管理界面,可以在这里创建、管理、查看bug 8.同时可以在bug统计界面来查看多角度的bug统计报表 9.测试管理界面,在这里可以直接创建测试流程,通过测试执行进行测试 10.应用发布界面,在这里发布你的应用 11.敏捷面板中的需求看板可以看到客户提的各种需求以及需求所在的流程位置 12.敏捷面板中的迭代看板,在此看板进行每次的迭代,既可以查看与迭代相关的需求,也可以在这里创建迭代中的所需处理的任务 MadPecker这个bug管理工具非常适合用于敏捷开发,尤其契合各类开发团队的办公方式,从功能上来看摒弃了一些办公软件花哨的东西把功能着重于实际,而且现在来看目前此软件属于刚上线,后续应该会有一些新功能的添加。

April 30, 2019 · 1 min · jiezi

浏览器触发保存密码条件

触发浏览器保存密码条件input[password]submit提交https(Firefox)关闭密码填充设置autocomplete无效值,有效值见https://developer.mozilla.org...注:autocomplete="off"是无效的,原因好像是chrome觉的他们更懂用户体验 nwjs设置保存密码chrome.privacy.services.passwordSavingEnabled.set({ value:true });

April 28, 2019 · 1 min · jiezi

hapi框架搭建记录三Joi数据校验和Sequelize数据迁移填充数据

hapi框架,用官网的简介来说就是:Hapi是构建应用程序和服务的丰富框架,它使开发人员能够专注于编写可重用的应用程序逻辑,而不是花时间构建基础设施。用自己的话简单来说,就是个类似express,koa之类的node服务基础框架。此篇博客是在阅读过掘金小册的《基于 hapi 的 Node.js 小程序后端开发实践指南》并实践操作后,以此记录实践过程和踩过的坑。感兴趣读者可支持阅读掘金小册原版的内容。Joi数据校验1.安装joi更多校验规则参考文档:https://www.npmjs.com/package...npm i @hapi/joi2.配合swagger只需要在路由的config配置校验信息,如./routes/test.js 新增多一条测试接口{ method: "GET", path: `/${GROUP_NAME}/get`, handler: (request, h) => { return { data: request.query }; }, config: { tags: ["api", GROUP_NAME], description: "测试get提交", notes: "配置Implementation说明文", validate: { query: { num: Joi.number() .integer() .required() .description("数字") .error(new Error("num参数错误")) } } } },3.swagger接口文档 Sequence的使用1.安装此案例链接mysql数据库,所以安装mysq2npm i sequelize-cli -Dnpm i sequelizenpm i mysql22.使用到的目录和文件├── config # 项目配置目录| ├── config.js # 数据库连接的配置(区分开发/生产环境)| ├── index.js # 暴露部分配置信息给app.js使用├── models # 数据库 model| ├── index.js # 数据库连接的样板代码├── migrations # 数据迁移的目录├── seeders # 数据填充的目录├── .env # 配置3.env配置数据库信息注意需要在本地mysql中创建对应的数据库, 如:hapi_db# 域名配置信息HOST = 127.0.0.1PORT = 3303# MySQL 数据库连接配置信息MYSQL_HOST = 127.0.0.1MYSQL_PORT = 3306MYSQL_DB_NAME = hapi_dbMYSQL_USERNAME = rootMYSQL_PASSWORD = 1234564. 暴露给入口文件使用的数据信息新建./config/index.jsconst { env } = process;module.exports = { host: env.HOST, port: env.PORT};5. 模式model使用新建./config/config.js给后台将要创建的数据库模型model使用的数据信息// 根据环境动态加载数据库配置信息// 本页面内容主要给数据库连接使用(../models/index.js)if (process.env.NODE_ENV == "production") { require("env2")("./.env.prod");} else { require("env2")("./.env");}const { env } = process;module.exports = { development: { username: env.MYSQL_USERNAME, password: env.MYSQL_PASSWORD, database: env.MYSQL_DB_NAME, host: env.MYSQL_HOST, port: env.MYSQL_PORT, dialect: "mysql", operatorsAliases: false }, production: { username: env.MYSQL_USERNAME, password: env.MYSQL_PASSWORD, database: env.MYSQL_DB_NAME, host: env.MYSQL_HOST, port: env.MYSQL_PORT, dialect: "mysql", operatorsAliases: false }};使用sequelize创建表1.数据库的创建sequelize提供创建数据库的命令,但最后还需要自己动手修改数据库格式为utf-8,所以还是手动直接创建方便2.migration创建表创建一个商品表 shops根据以下命令,将会自动创建./migration/2019XXXXXXXXX-create-shops-table.js其实是可以直接在mysql创建表并填写数据,但这里使用migration来创建主要为了留下对表的创建修改等记录,未来有查询依据。就类比记录创建日志。./node_modules/.bin/sequelize migration:create --name create-shops-tablexxxx-crate.shops.table.js"use strict";module.exports = { up: (queryInterface, Sequelize) => { return queryInterface.createTable("shops", { id: { type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true }, name: { type: Sequelize.STRING, allowNull: false }, thumb_url: Sequelize.STRING, created_at: Sequelize.DATE, updated_at: Sequelize.DATE }); }, down: (queryInterface, Sequelize) => {face.dropTable("shops"); }};3. 向mysql数据库中创建表在项目根目录下执行命令./node_modules/.bin/sequelize db:migrate成功创建示例 ...

April 28, 2019 · 2 min · jiezi

hapi框架搭建记录二路由改造和生成接口文档

hapi框架,用官网的简介来说就是:Hapi是构建应用程序和服务的丰富框架,它使开发人员能够专注于编写可重用的应用程序逻辑,而不是花时间构建基础设施。用自己的话简单来说,就是个类似express,koa之类的node服务基础框架。此篇博客是在阅读过掘金小册的《基于 hapi 的 Node.js 小程序后端开发实践指南》并实践操作后,以此记录实践过程和踩过的坑。感兴趣读者可支持阅读掘金小册原版的内容。路由汇总1. 在./routes目录下新建index.js作为路由的汇总,这样以后只管在./routes下新建文件即可"use strict";const fs = require("fs");const path = require("path");const basename = path.basename(__filename); // 当前文件名let routeArr = [];// 同步读取当前目录,并过滤除了当前文件的文件名数组fs.readdirSync(__dirname) .filter(file => { // 过滤掉隐藏文件、当前文件、非js文件, 返回当前目录下文件名称数组 return ( file.indexOf(".") !== 0 && file !== basename && file.slice(-3) === ".js" ); }) .forEach(file => { // 引入路由模块 let arr = require(path.join(__dirname, file)); // 汇总 routeArr.push(...arr); });module.exports = routeArr;测试路由1.新建test.js文件作为测试const GROUP_NAME = "test";module.exports = [ // 纯测试返回 接口 { method: "GET", path: `/${GROUP_NAME}`, handler: (request, h) => { const data = { message: "test" }; // 响应数据方式: // return h.response(data).code(200); return data; } },]2.修改app.js ...

April 28, 2019 · 1 min · jiezi

Chrome-小恐龙游戏源码探究完-游戏结束和其他要素

文章首发于我的个人博客前言上一篇文章:《Chrome 小恐龙游戏源码探究九 -- 游戏碰撞检测》实现了游戏的碰撞检测,这一篇文章中将利用碰撞检测的结果,实现游戏的结束。 绘制 Game Over 面板这个游戏结束时的 Game Over 面板是通过 GameOverPanel 类绘制的。 定义 GameOverPanel 类: /** * 游戏结束面板类 * @param {!HTMLCanvasElement} 画布元素 * @param {Object} textImgPos 文字 "Game Over" 在雪碧图中的位置 * @param {Object} restartImgPos 重置按钮在雪碧图中的位置 * @param {!Object} dimensions 游戏画布的尺寸 */function GameOverPanel(canvas, textImgPos, restartImgPos, dimensions) { this.canvas = canvas; this.ctx = canvas.getContext('2d'); this.canvasDimensions = dimensions; this.textImgPos = textImgPos; this.restartImgPos = restartImgPos; this.draw();};相关的配置参数,以及原型链上的方法: // 配置参数GameOverPanel.dimensions = { TEXT_X: 0, // 文字 "Game Over" 的 x 坐标 TEXT_Y: 13, TEXT_WIDTH: 191, // 文字 "Game Over" 的宽度 TEXT_HEIGHT: 11, RESTART_WIDTH: 36, // 重置按钮的宽度 RESTART_HEIGHT: 32,};GameOverPanel.prototype = { draw: function() { var dimensions = GameOverPanel.dimensions; var centerX = this.canvasDimensions.WIDTH / 2; // 文字 "Game Over" var textSourceX = dimensions.TEXT_X; var textSourceY = dimensions.TEXT_Y; var textSourceWidth = dimensions.TEXT_WIDTH; var textSourceHeight = dimensions.TEXT_HEIGHT; var textTargetX = Math.round(centerX - (dimensions.TEXT_WIDTH / 2)); var textTargetY = Math.round((this.canvasDimensions.HEIGHT - 25) / 3); var textTargetWidth = dimensions.TEXT_WIDTH; var textTargetHeight = dimensions.TEXT_HEIGHT; // 重置按钮 var restartSourceWidth = dimensions.RESTART_WIDTH; var restartSourceHeight = dimensions.RESTART_HEIGHT; var restartTargetX = centerX - (dimensions.RESTART_WIDTH / 2); var restartTargetY = this.canvasDimensions.HEIGHT / 2; textSourceX += this.textImgPos.x; textSourceY += this.textImgPos.y; // 文字 "Game over" this.ctx.drawImage(Runner.imageSprite, textSourceX, textSourceY, textSourceWidth, textSourceHeight, textTargetX, textTargetY, textTargetWidth, textTargetHeight); // 重置按钮 this.ctx.drawImage(Runner.imageSprite, this.restartImgPos.x, this.restartImgPos.y, restartSourceWidth, restartSourceHeight, restartTargetX, restartTargetY, dimensions.RESTART_WIDTH, dimensions.RESTART_HEIGHT); }};然后需要在游戏结束时,调用 GameOverPanel 类。 ...

April 27, 2019 · 3 min · jiezi

前端面试题甄选持续更新

2019.04.23 已知如下代码,如何修改才能让图片宽度为 300px ?注意下面代码不可修改<img src="1.jpg" style="width:480px!important;”>解决方案: css3的缩放: transform(scale(0.625, 0.625));js: document.getElementsByTagName("img")[0].setAttribute("style","width:300px!important;")css: max-width: 300px; (这个我当时没想到...)css: box-sizing: border-box; padding-left: 90px; padding-right: 90px; (这个我当时也没想到...)2019.03.22 Promise 构造函数是同步执行还是异步执行,那么 then 方法呢?这个很明显,promise构造函数是同步执行的,then方法是异步执行的。我从回答中选了个稍微复杂点的例子: const promise = new Promise((resolve, reject) => { console.log(1); resolve(5); console.log(2);}).then(val => { console.log(val);});promise.then(() => { console.log(3);});console.log(4);setTimeout(function() { console.log(6);});//执行结果: 124536这里会牵涉一个宏任务(macrotask)和微任务(microtask)的执行顺序问题,进而牵出javascript的事件循环(EventLoop)。 上干货:这一次,彻底弄懂 JavaScript 执行机制,阮一峰 JavaScript 运行机制详解:再谈Event Loop不想看的也可以直接看这里:先执行一个宏任务(其实运行js的时候这个宏任务已经在运行),然后执行微任务,清空微任务队列,再执行宏任务,再执行微任务,清空微任务队列... 常见的任务类型: 微任务 microtask(jobs): promise / ajax / Object.observe(该方法已废弃)宏任务 macrotask(task): setTimout / script / IO / UI Rendering

April 27, 2019 · 1 min · jiezi

Chrome-小恐龙游戏源码探究九-游戏碰撞检测

文章首发于我的个人博客前言上一篇文章:《Chrome 小恐龙游戏源码探究八 -- 奔跑的小恐龙》实现了小恐龙的绘制以及键盘对小恐龙的控制,这一篇文章中将实现游戏的碰撞检测。 碰撞检测原理这个游戏采用的检测方法是盒子碰撞,这种检测方法最大的好处就是简单,但是缺点是不够精确。 首先,如果将小恐龙和障碍物分别看作两个大的盒子,那么进行碰撞检测的效果如下: 可以看出,两个盒子虽然有重叠部分,但是实际小恐龙并没有和障碍物相撞。 所以想要进行更精确的检测,需要把物体拆分成多个较小的盒子。例如: 但是拆分的时候也不能过于细致,否则运算的时候,很影响性能。 这个游戏中所进行的必要拆分如图所示: 这里值得一提的是,当小恐龙俯身时,只需要将其拆成一个大的盒子。因为当小恐龙俯身时,可以产生碰撞的部分只有前面,而在小恐龙前面碰撞一定会碰到它的头部。毕竟现在这个游戏中还没有那么矮小的障碍物,以至于刚好碰到小恐龙俯身时的下巴。 这就提示我们,如果想要对游戏进行扩展,添加新的障碍物,就要考虑到小恐龙当前的碰撞盒子是否需要进行调整,要确保当前的碰撞盒子可以正确检测出所有情况。 生成碰撞盒子游戏中使用 CollisionBox 类来生成碰撞盒子: /** * 用于生成碰撞盒子 * @param {Number} x X 坐标 * @param {Number} y Y坐标 * @param {Number} w 宽度 * @param {Number} h 高度 */function CollisionBox(x, y, w, h) { this.x = x; this.y = y; this.width = w; this.height = h;};小恐龙的碰撞盒子如下: // 小恐龙的碰撞盒子Trex.collisionBoxes = { DUCKING: [ new CollisionBox(1, 18, 55, 25) ], RUNNING: [ new CollisionBox(22, 0, 17, 16), new CollisionBox(1, 18, 30, 9), new CollisionBox(10, 35, 14, 8), new CollisionBox(1, 24, 29, 5), new CollisionBox(5, 30, 21, 4), new CollisionBox(9, 34, 15, 4) ]};障碍物的碰撞盒子如下: ...

April 27, 2019 · 4 min · jiezi

Chrome-小恐龙游戏源码探究七-昼夜模式交替

文章首发于我的个人博客 前言上一篇文章:《Chrome 小恐龙游戏源码探究六 -- 记录游戏分数》实现了游戏分数、最高分数的记录和绘制。这一篇文章中将实现昼夜模式交替的的效果。 夜晚模式定义夜晚模式类 NightMode: /** * 夜晚模式 * @param {HTMLCanvasElement} canvas 画布 * @param {Object} spritePos 雪碧图中的坐标信息 * @param {Number} containerWidth 容器宽度 */function NightMode(canvas, spritePos, containerWidth) { this.canvas = canvas; this.ctx = this.canvas.getContext('2d'); this.spritePos = spritePos; this.containerWidth = containerWidth; this.xPos = containerWidth - 50; // 月亮的 x 坐标 this.yPos = 30; // 月亮的 y 坐标 this.currentPhase = 0; // 月亮当前所处的时期 this.opacity = 0; // 星星和月亮的透明度 this.stars = []; // 存储星星 this.drawStars = false; // 是否绘制星星 // 放置星星 this.placeStars();}相关的配置参数: ...

April 26, 2019 · 4 min · jiezi

Chrome-小恐龙游戏源码探究八-奔跑的小恐龙

文章首发于我的个人博客 前言上一篇文章:《Chrome 小恐龙游戏源码探究七 -- 昼夜模式交替》实现了游戏昼夜模式的交替,这一篇文章中,将实现:1、小恐龙的绘制 2、键盘对小恐龙的控制 3、页面失焦后,重新聚焦会重置小恐龙的状态 绘制静态的小恐龙定义小恐龙类: /** * 小恐龙类 * @param {HTMLCanvasElement} canvas 画布 * @param {Object} spritePos 图片在雪碧图中的坐标 */function Trex(canvas, spritePos) { this.canvas = canvas; this.ctx = canvas.getContext('2d'); this.spritePos = spritePos; this.xPos = 0; this.yPos = 0; this.groundYPos = 0; // 小恐龙在地面上时的 y 坐标 this.currentFrame = 0; // 当前的动画帧 this.currentAnimFrames = []; // 存储当前状态的动画帧在雪碧图中的 x 坐标 this.blinkDelay = 0; // 眨眼间隔的时间(随 机) this.blinkCount = 0; // 眨眼次数 this.animStartTime = 0; // 小恐龙眨眼动画开始时间 this.timer = 0; // 计时器 this.msPerFrame = 1000 / FPS; // 帧率 this.status = Trex.status.WAITING; // 当前的状态 this.config = Trex.config; this.jumping = false; // 是否跳跃 this.ducking = false; // 是否闪避(俯身) this.jumpVelocity = 0; // 跳跃的速度 this.reachedMinHeight = false; // 是否达到最低高度 this.speedDrop = false; // 是否加速下降 this.jumpCount = 0; // 跳跃的次数 this.jumpspotX = 0; // 跳跃点的 x 坐标 this.init();}相关的配置参数: ...

April 26, 2019 · 7 min · jiezi

Chrome-小恐龙游戏源码探究五-随机绘制障碍

前言上一篇文章:《Chrome 小恐龙游戏源码探究四 -- 随机绘制云朵》 实现了云朵的随机绘制,这一篇文章中将实现:1、仙人掌、翼龙障碍物的绘制 2、游戏速度的改变 障碍物的类型有两种:仙人掌和翼龙。翼龙每次只能有一只,高度随机,仙人掌一次可以绘制多个,一次绘制的数目随机。对于绘制障碍物的关键是:保证合适的大小和间隔。例如:不能在游戏刚开始速度很慢的时候就绘制一个很宽的障碍物,否则是跳不过去的。也不能在游戏速度较快的情况下,两个障碍物间隔生成的很窄,否则当跳过第一个障碍物后,一定会撞到下一个障碍物。 有关障碍物的碰撞检测部分这里先不实现,会放在后面的单独一章来讲。障碍物类 Obstacle定义 Obstacle 类: /** * 障碍物类 * @param {HTMLCanvasElement} canvas 画布 * @param {String} type 障碍物类型 * @param {Object} spriteImgPos 在雪碧图中的位置 * @param {Object} dimensions 画布尺寸 * @param {Number} gapCoefficient 间隙系数 * @param {Number} speed 速度 * @param {Number} opt_xOffset x 坐标修正 */function Obstacle(canvas, type, spriteImgPos, dimensions, gapCoefficient, speed, opt_xOffset) { this.canvas = canvas; this.ctx = canvas.getContext('2d'); this.typeConfig = type; // 障碍物类型 this.spritePos = spriteImgPos; // 在雪碧图中的位置 this.gapCoefficient = gapCoefficient; // 间隔系数 this.dimensions = dimensions; // 每组障碍物的数量(随机 1~3 个) this.size = getRandomNum(1, Obstacle.MAX_OBSTACLE_LENGTH); this.xPos = dimensions.WIDTH + (opt_xOffset || 0); this.yPos = 0; this.remove = false; // 是否可以被删除 this.gap = 0; // 间隙 this.speedOffset = 0; // 速度修正 // 非静态障碍物的属性 this.currentFrame = 0; // 当前动画帧 this.timer = 0; // 动画帧切换计时器 this.init(speed);}障碍物的有关参数: ...

April 26, 2019 · 5 min · jiezi

Chrome-小恐龙游戏源码探究四-随机绘制云朵

前言上一篇文章:《Chrome 小恐龙游戏源码探究三 -- 进入街机模式》 实现了开场动画和街机模式。这一篇文章中,将实现云朵的随机绘制。 云朵类 Cloud定义云朵类 Cloud: /** * 云朵类 * @param {HTMLCanvasElement} canvas 画布 * @param {Object} spritePos 图片在雪碧图中的位置信息 * @param {Number} containerWidth 容器的宽度 */function Cloud(canvas, spritePos, containerWidth) { this.canvas = canvas; this.ctx = canvas.getContext('2d'); this.spritePos = spritePos; this.containerWidth = containerWidth; // 坐标 this.xPos = containerWidth; this.yPos = 0; // 该云朵是否需要删除 this.remove = false; // 随机云朵之间的间隙 this.cloudGap = getRandomNum(Cloud.config.MIN_CLOUD_GAP, Cloud.config.MAX_CLOUD_GAP); this.init();}相关的配置参数: Cloud.config = { WIDTH: 46, HEIGHT: 14, MIN_CLOUD_GAP: 100, // 云之间的最小间隙 MAX_CLOUD_GAP: 400, // 云之间的最大间隙 MIN_SKY_LEVEL: 71, // 云的最小高度 MAX_SKY_LEVEL: 30, // 云的最大高度 BG_CLOUD_SPEED: 0.2, // 云的速度 CLOUD_FREQUENCY: 0.5, // 云的频率 MAX_CLOUDS: 6 // 云的最大数量};补充本篇文章中会用到的一些数据: ...

April 26, 2019 · 3 min · jiezi

Chrome-小恐龙游戏源码探究六-记录游戏分数

前言上一篇文章:《Chrome 小恐龙游戏源码探究五 -- 随机绘制障碍》 实现了障碍物仙人掌和翼龙的绘制。这一篇将实现当前分数、最高分数的记录和绘制。 在游戏中,小恐龙移动的距离就是游戏的分数。分数每达 100,就会有闪动的特效。首次进行游戏的时候,由于没有记录过游戏的历史得分,所以不会显示最高分,只有当第一次 game over 后才能显示历史最高分。 分数记录定义分数类: /** * 记录移动的距离(分数等于移动距离) * @param {HTMLCanvasElement} canvas 画布 * @param {Object} spritePos 图片在雪碧图中的位置 * @param {Number} canvasWidth 画布的宽度 */function DistanceMeter(canvas, spritePos, canvasWidth) { this.canvas = canvas; this.ctx = canvas.getContext('2d'); this.config = DistanceMeter.config; this.spritePos = spritePos; this.x = 0; // 分数显示在 canvas 中的 x 坐标 this.y = 5; this.maxScore = 0; // 游戏分数上限 this.highScore = []; // 存储最高分数的每一位数字 this.digits = []; // 存储分数的每一位数字 this.achievement = false; // 是否进行闪动特效 this.defaultString = ''; // 游戏的默认距离(00000) this.flashTimer = 0; // 动画计时器 this.flashIterations = 0; // 特效闪动的次数 this.maxScoreUnits = this.config.MAX_DISTANCE_UNITS; // 分数的最大位数 this.init(canvasWidth);}有关的配置参数: ...

April 26, 2019 · 4 min · jiezi

Chrome-小恐龙游戏源码探究三-进入街机模式

前言上一篇文章:《Chrome 小恐龙游戏源码探究二 -- 让地面动起来》 实现了地面的移动。这一篇文章中,将实现效果:1、浏览器失焦时游戏暂停,聚焦游戏继续。 2、开场动画。 3、进入街机模式。 街机模式的效果就是:游戏开始后,进入全屏模式。例如: 可以看到,进入街机模式之前,有一段开场动画。我们先来实现一下这个开场动画。 这里先只实现地面的开场动画,小恐龙的后续再去实现。实现开场动画首先修改 CSS 样式: .offline .runner-container { position: absolute; top: 35px;- width: 100%;+ width: 44px; max-width: 600px; height: 150px; overflow: hidden;}让 canvas 初始只显示 44px 的宽度。 然后在 Runner 的原型链上添加方法: Runner.prototype = { /** * 游戏被激活时的开场动画 * 将 canvas 的宽度调整到最大 */ playIntro: function () { if (!this.activated && !this.crashed) { this.playingIntro = true; // 正在执行开场动画 // 定义 CSS 动画关键帧 var keyframes = '@-webkit-keyframes intro { ' + 'from { width:' + Trex.config.WIDTH + 'px }' + 'to { width: ' + this.dimensions.WIDTH + 'px }' + '}'; // 将动画关键帧插入页面中的第一个样式表 document.styleSheets[0].insertRule(keyframes, 0); this.containerEl.style.webkitAnimation = 'intro .4s ease-out 1 both'; this.containerEl.style.width = this.dimensions.WIDTH + 'px'; // 监听动画。当触发结束事件时,设置游戏为开始状态 this.containerEl.addEventListener(Runner.events.ANIMATION_END, this.startGame.bind(this)); this.setPlayStatus(true); // 设置游戏为进行状态 this.activated = true; // 游戏彩蛋被激活 } else if (this.crashed) { // 这个 restart 方法的逻辑这里先不实现 this.restart(); } }, /** * 更新游戏为开始状态 */ startGame: function () { this.playingIntro = false; // 开场动画结束 this.containerEl.style.webkitAnimation = ''; },};需要补充一些数据: ...

April 26, 2019 · 3 min · jiezi

Chrome-小恐龙游戏源码探究二-让地面动起来

前言上一篇文章:《Chrome 小恐龙游戏源码探究一 -- 绘制静态地面》 中定义了游戏的主体类 Runner,并实现了静态地面的绘制。这一篇文章中,将实现效果:1、地面无限滚动。2、刚开始地面不动,按下空格后地面滚动。 地面无限滚动要实现地面的移动就要不断更新地面的 x 坐标。定义方法: HorizonLine.prototype = { /** * 更新地面的 x 坐标 * @param {Number} pos 地面的位置 * @param {Number} incre 移动距离 */ updateXPos: function (pos, incre) { var line1 = pos; var line2 = pos === 0 ? 1 : 0; // 第一段地面向左移动,第二段地面随之 this.xPos[line1] -= incre; this.xPos[line2] = this.xPos[line1] + this.dimensions.WIDTH; // 第一段地面移出了 canvas if (this.xPos[line1] <= -this.dimensions.WIDTH) { // 将第一段地面放到 canvas 右侧 this.xPos[line1] += this.dimensions.WIDTH * 2; // 此时第二段地面的 x 坐标刚好和 canvas 的 x 坐标对齐 this.xPos[line2] = this.xPos[line1] - this.dimensions.WIDTH; // 给放到 canvas 后面的地面随机地形 this.sourceXPos[line1] = this.getRandomType() + this.spritePos.x; } }, /** * 获取随机的地形 */ getRandomType: function () { return Math.random() > this.bumpThreshold ? this.dimensions.WIDTH : 0; },};其中 updateXPos 实现了地面 x 坐标的更新。当第一段地面移出 canvas 时,会将第一段地面 x 坐标乘 2 放到 canvas 后面,然后为其随机地形。这时,原来的第二段地面就变成了第一段地面继续向前移动,以此类推。这样就实现了地面的不断移动和更新。 ...

April 26, 2019 · 3 min · jiezi