Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2019.7.22 - 7.28 中你学到什么? #3

Open
KieSun opened this issue Jul 22, 2019 · 61 comments
Open

2019.7.22 - 7.28 中你学到什么? #3

KieSun opened this issue Jul 22, 2019 · 61 comments

Comments

@KieSun
Copy link
Owner

KieSun commented Jul 22, 2019

No description provided.

@xuhongbo
Copy link

xuhongbo commented Jul 22, 2019

mac环境下,命令行杀死特定node服务

由于在前端开发的时候,几个项目来回切换,难免会有端口占用的情况,之前的做法都是手动查找,由于比较麻烦,所以自己搞了个命令,一行搞定

lsof -i tcp:8080 | grep LISTEN | awk '{print $2}'| awk -F"/" '{ print $1 }' | xargs kill -9

上面举例的是杀死 8080 端口,有更好的方式,欢迎讨论

@KieSun
Copy link
Owner Author

KieSun commented Jul 22, 2019

mac环境下,命令行杀死特定node服务

由于在前端开发的时候,几个项目来回切换,难免会有端口占用的情况,之前的做法都是手动查找,由于比较麻烦,所以自己搞了个命令,一行搞定

lsof -i tcp:8080 | grep LISTEN | awk '{print $2}'| awk -F"/" '{ print $1 }' | xargs kill -9

上面举例的是杀死 8080 端口,有更好的方式,欢迎讨论

很实用,可以做成 npm 命令,然后传参替换端口号

@xnng
Copy link

xnng commented Jul 22, 2019

@KieSun

好像已经有人做了,我试了下,在 windows 环境下第二个库是可以用的,第一个库无效。
image

2019-07-22_14-18-27

@bytemain
Copy link

Windows 下关于端口被占用而又找不到被占用的程序的解决办法

之前用 SSR 的时候,有时候开机提示 1080 端口被占用,查看这个端口确实没被占用,遂不了了之。
今天用 WSL , 又出现了这个问题,一直报 3000 端口被占用,百度了很久,执行下面这句即可。

netsh winsock reset 

知识点分析:

netsh 是从windows xp sp2开始提供的功能强大的网络配置命令行工具。 是一个能够通过命令行操作几乎所有网络相关设置的接口,比如设置IP,DNS,网卡,无线网络等。

winsock是Windows网络编程接口,winsock工作在应用层,它提供与底层传输协议无关的高层数据传输编程接口。reset是对Winsock的重置操作。当执行完winsock的命令重启计算机后,需要重新配置IP等网络配置信息。
netsh winsock reset 是把它恢复到默认状态。作用是重置 Winsock 目录。如果一台机器上的Winsock协议配置有问题的话将会导致网络连接等问题,可通过使用netsh winsock reset命令来重置Winsock目录尝试恢复。这个命令可以重新初始化网络环境,以解决由于软件冲突、病毒原因造成的参数错误问题。例如电脑突然出现成功连接网络但不能上网、网络受限,打开网页出现显示问题,无法自动获取IP地址或指定IP地址仍无数据包传输,使用蓝牙适配器传输文件时提示“使用了与请求的协议不兼容的地址”等等网络协议应用相关故障。

输入netsh winsock reset命令,有何副作用

netsh winsock reset这个命令可以重新初始化网络环境,以解决由于软件冲突、病毒原因造成的参数错误问题。当执行完winsock的命令重启计算机后,需要重新配置IP。局域网的话需要DNS选择一下,另外因机而异可能会断网或网速变慢,这个就需要继续再进行解决了。

@soraliu
Copy link

soraliu commented Jul 22, 2019

Linux下通过命令行替换文本

# 将wxml文件的i标签替换为text
grep '<i ' -rl . --include='*.wxml' --exclude-dir=node_module --exclude-dir=dist | xargs sed -i -e 's/<i /<text /g'
grep '</i>' -rl . --include='*.wxml' --exclude-dir=node_module --exclude-dir=dist | xargs sed -i -e 's/<\/i>/<\/text>/g'

@KieSun
Copy link
Owner Author

KieSun commented Jul 22, 2019

@lengthmin 感谢分享!提出问题、问题的原因以及解决办法是一件很好的事情。
@LOVESORA 感谢分享!

@erdong0604
Copy link

erdong0604 commented Jul 22, 2019

图片懒加载

<ul>
	<li><img src="./img/default.png" data="./img/1.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/2.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/3.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/4.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/5.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/6.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/7.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/8.png" alt=""></li>
</ul>
let imgs =  document.querySelectorAll('img')
// 窗口可视区高度
let clientHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
// img 距离窗口可视区顶部的距离 imgs[i].getBoundingClientRect().top
function lazyLoadImg () {
    for (let i = 0; i < imgs.length; i ++) {
        if((imgs[i].getBoundingClientRect().top + imgs[i].height)>=0&&imgs[i].getBoundingClientRect().top < clientHeight ){
            imgs[i].src = imgs[i].getAttribute('data')
        }
    }      
}
window.addEventListener('scroll', lazyLoadImg);

@princewck
Copy link

@erdong0604 可以在js里预先加载图片,防止直接替换src图片在下载过程中闪白一下的问题

图片懒加载

<ul>
	<li><img src="./img/default.png" data="./img/1.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/2.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/3.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/4.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/5.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/6.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/7.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/8.png" alt=""></li>
</ul>
let imgs =  document.querySelectorAll('img')
// 窗口可视区高度
let clientHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
// img 距离窗口可视区顶部的距离 imgs[i].getBoundingClientRect().top
function lazyLoadImg () {
 for (let i = 0; i < imgs.length; i ++) {
     if((imgs[i].getBoundingClientRect().top + imgs[i].height)>=0&&imgs[i].getBoundingClientRect().top < clientHeight ){
        const imgUrl = imgs[i].getAttribute('data');
        _preloadImg(imgUrl, function () {
           imgs[i].src = imgUrl;
        }, function () {
           imgs[i].src = '/img/loaderror.jpg';
        });
     }
 }      
}

function _preloadImg(url, callback, onerror) {
  const img = new Image();
  img.src = url;
  img.onload = function () {
    if (callback) {
      callback();
    }
  }
  img.onerror = function () {
    if (onerror) {
      onerror();
    }
  }
}
window.addEventListener('scroll', lazyLoadImg);

@princewck
Copy link

用gitHooks约束 commit message

之前有用过,这周看 vue-cli 源码发现了如下的 verify commit message 逻辑,觉得挺实用的,特别适合对项目有追求的强迫症患者或者多人合作的项目约束风格的统一。

const chalk = require('chalk')  // eslint-disable-line
const msgPath = process.env.GIT_PARAMS
const msg = require('fs').readFileSync(msgPath, 'utf-8').trim()

const commitRE = /^(v\d+\.\d+\.\d+(-(alpha|beta|rc.\d+))?)|((revert: )?(feat|fix|docs|style|refactor|perf|test|workflow|ci|chore|types)(\(.+\))?!?: .{1,50})/

if (!commitRE.test(msg)) {
  console.log()
  console.error(
    `  ${chalk.bgRed.white(' ERROR ')} ${chalk.red(`invalid commit message format.`)}\n\n` +
    chalk.red(`  Proper commit message format is required for automated changelog generation. Examples:\n\n`) +
    `    ${chalk.green(`feat(compiler): add 'comments' option`)}\n` +
    `    ${chalk.green(`fix(v-model): handle events on blur (close #28)`)}\n\n` +
    chalk.red(`  See .github/COMMIT_CONVENTION.md for more details.\n`) +
    chalk.red(`  You can also use ${chalk.cyan(`npm run commit`)} to interactively generate a commit message.\n`)
  )
  process.exit(1)
}

要使上面的逻辑生效,我们还需要安装 yorkie

npm install yorkie --save-dev

然后在项目的 package.json 中加入以下配置

{
  "gitHooks": {
    "commit-msg": "node scripts/verifyCommitMessage.js"
  },
}

到此我们就配置完成了

脚本的作用是限制 commit 信息必须是 feat|fix|docs|style|refactor|perf|test|workflow|ci|chore|types打头,或者版本号开头,看vue-cli的提交记录更直观
image

配置完成后我们要是不按照约定的格式书写commit message,提交就会被挡住,看下图:
image

相关原理可以参看 Git hooks,我们引入的第三方库安装后会在仓库的.git/hooks目录下为我们设置一些hooks脚本,这些hooks脚本的任务是接管我们的node或shell脚本,使其在正确的时机执行,为我们隐藏了直接自己在./git/hooks路径下编写hook脚本的复杂性

你还可以指定在commit前做一些预处理(pre-commit),比如执行eslint,对git提交做进一步的规范和约束,详细用法请阅读文档。

类似的工具还有 husky

@erdong0604
Copy link

@erdong0604 可以在js里预先加载图片,防止直接替换src图片在下载过程中闪白一下的问题

图片懒加载

<ul>
	<li><img src="./img/default.png" data="./img/1.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/2.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/3.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/4.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/5.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/6.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/7.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/8.png" alt=""></li>
</ul>
let imgs =  document.querySelectorAll('img')
// 窗口可视区高度
let clientHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
// img 距离窗口可视区顶部的距离 imgs[i].getBoundingClientRect().top
function lazyLoadImg () {
 for (let i = 0; i < imgs.length; i ++) {
     if((imgs[i].getBoundingClientRect().top + imgs[i].height)>=0&&imgs[i].getBoundingClientRect().top < clientHeight ){
        const imgUrl = imgs[i].getAttribute('data');
        _preloadImg(imgUrl, function () {
           imgs[i].src = imgUrl;
        }, function () {
           imgs[i].src = '/img/loaderror.jpg';
        });
     }
 }      
}

function _preloadImg(url, callback, onerror) {
  const img = new Image();
  img.src = url;
  img.onload = function () {
    if (callback) {
      callback();
    }
  }
  img.onerror = function () {
    if (onerror) {
      onerror();
    }
  }
}
window.addEventListener('scroll', lazyLoadImg);

@princewck good

@KRISACHAN
Copy link

KRISACHAN commented Jul 22, 2019

2019/7/12份学习

无loop生成指定长度的数组

const List1 = len => ''.padEnd(len, ',').split('.')

const List2 = len => [...new Array(len).keys()]

@shfshanyue
Copy link

shfshanyue commented Jul 22, 2019

2019/07/22

01 graphql 中多级分页查询时的 N+1 问题

此处只能在客户端避免多层分页查询,而当有恶意查询时会加大服务器压力。可以使用 Hash Query 避免此类问题,避免暴露原始 Query,同时也在生产环境禁掉 introspection

{
  users (page: 1, pageSize: 3) {
    id
    todos (page: 1, pageSize: 3) {
      id 
      name
    } 
  }
}
select id from users limit 3

select id, name from todo where user_id = 1 limit 3
select id, name from todo where user_id = 2 limit 3
select id, name from todo where user_id = 3 limit 3

记录

02 在前端中把 gql 统一管理减小打包体积

准确说,已经把 gql 统一管理为 query.gql,通过 loader 引入,会被打入 common.js
而在个别页面又单独通过 graphql-tag 引入,被按需加载打包,而此时 graphql-tag 又依赖 graphql,gql 统一管理后,此时的两个模块的依赖也就没有了。

通过 webpack 分析,gzip 后的总体积变化: 191.64KB -> 176.51KB,体积缩减还是比较可观的。

优化记录

03 获取当前 commit hash

可以通过 npm scripts 注入到项目中,方便集成到 sentrylogger 等工具组件中

git rev-parse --verify HEAD  | cut -c 1-8

后来找到更简单的命令 git rev-parse --short HEAD

2019/07/23

01 本地更好的流式日志格式化

服务器端的日志很重要,一般设置为 jsonl 格式,方便在 elk 上查询或者使用 spark 分析。而在本地调试时就不是很直观了,而日志又是 stream 的数据。此时可以使用 jq 对日志进行美化

# 实时查看日志,并且只关注 message 字段
tail -f logs/db.log | jq '{message}'

此时你不仅有了更好的可视化,而且只需要关注你自己关心的字段就可以了,体验很棒

02 Intersection Observel 做路由页面预加载与图片懒加载

由于我的网站使用了 next.js 的技术栈,最近对 next 升级到了 v9,对 next 一直有所关注。在今天读了 Next.9 features,其中有一个点:

Next.js 9 will automatically prefetch components as they appear in-viewport.

其中原理便是使用 Intersection Observel 来监听元素是否出现在当前可视窗口内。 Next.js 可以对新的页面资源做懒加载,举一反三,我们也可以使用它对图片做懒加载。

03 了解一个 APP 从开发到盈利所经历的事

2019/07/24

01 在 React 中使用 React.Fragment 或者 <></> 包含多个子元素

恩,这个是查看某项目代码时看到的,虽然一直知道了 react 目前已经可以包含多元素,但也没有细究,今天偶然得知,受用很多。

(
  <>
    <td>Hello</td>
    <td>World</td>
  </>
);

02 sar (System Activity Monitor)

sarvmstatiostat 相比,不仅可以实时监控 linux 系统 IO/memory/cpu 等的信息,而且可以 获取一段时间内的系统统计信息,比如他可以获取一天时间内的 CPU 使用率。我也把它记录在了我的博客里

linux 指标监控

03 Apollo Federation & GraphQL Gateway

简而言之,Apollon Federation 可以把多个 graphql service 组合成一个 API Gateway。如果公司的所有业务与微服务都使用了 GraphQL,则它正好可以做一个不错的服务整合,这还挺令人兴奋的。

2019/07/25

总结了LF 与 CRLF 的一篇文章

了解一些底层知识,视野会开阔很多。如本篇文章可以通过系统调用来看换行符到底是什么。

用户增长模型 RARRA

我的理解,用户留存比较重要,应作为着力点

2019/07/26

了解 vuepress 如何写插件,并给我的博客写了一个归档的插件

https://github.com/shfshanyue/blog/blob/master/.vuepress/config.js

2019/07/27

尝试使用 netlify 新建了我的博客

博客地址 https://shanyue.netlify.com/

至于我现在的博客还是使用 hugo 构建,不得不说 hugo 的构建速度真是很快。另外使用自建的 gitlab,gitlab-ci,docker-compose 来做自动部署,不得不说运维这些还是有些成本的。而 netlify 就简单很多了,这些运维工作都不需要你来关心。

云是一种趋势,以后考虑能够 SAAS 化的服务全部 SAAS 化。

graphql-code-generator 自动为前端生成 graphql schema 相对应的 ts 的 type

毫无疑问,前端不用手动配置关于接口的 interface,大大解放了前端的生产力,而且减少了失误率。

2019/07/28

了解关于 IO 复用的几种机制

@guanweiwang
Copy link

mac环境下,命令行杀死特定node服务

由于在前端开发的时候,几个项目来回切换,难免会有端口占用的情况,之前的做法都是手动查找,由于比较麻烦,所以自己搞了个命令,一行搞定

lsof -i tcp:8080 | grep LISTEN | awk '{print $2}'| awk -F"/" '{ print $1 }' | xargs kill -9

上面举例的是杀死 8080 端口,有更好的方式,欢迎讨论

我都是全杀 killall node

@Flcwl
Copy link

Flcwl commented Jul 22, 2019

mac环境下,命令行杀死特定node服务

由于在前端开发的时候,几个项目来回切换,难免会有端口占用的情况,之前的做法都是手动查找,由于比较麻烦,所以自己搞了个命令,一行搞定

lsof -i tcp:8080 | grep LISTEN | awk '{print $2}'| awk -F"/" '{ print $1 }' | xargs kill -9

上面举例的是杀死 8080 端口,有更好的方式,欢迎讨论

@xuhongbo awk -F"/" '{ print $1 }' 这部分命令解释一下,没懂

@Bulandent
Copy link

Javascript隐式类型转换
https://juejin.im/post/5bc5c752f265da0a9a399a62

[] == ![] // true
[] == 0 // true
[2] == 2 // true
['0'] == false // true
'0' == false // true
[] == false // true
[null] == 0 // true
null == 0 // false
[null] == false // true
null == false // false
[undefined] == false // true
undefined == false // false

@teachat8
Copy link

毕业两年我的感悟:

  • 自身的实力最重要,要有一样核心技能,其他方面也要有所涉猎。
  • 公司带给个人的影响是很大的,如果一个公司不愿意培养你,真的不值得去付出。
  • 沟通确实很重要,沟通不明确会导致接下来一系列的问题。
  • 说话是后天锻炼出来的,多和人交流,话到嘴边留三分。
  • 不用讨厌加班,人与人拉开差距就在下班后的几个小时,加班可以学习啊。雷军还说过你拿3000块钱换我一个月的青春,多不划算。

@KieSun
Copy link
Owner Author

KieSun commented Jul 22, 2019

毕业两年我的感悟:

  • 自身的实力最重要,要有一样核心技能,其他方面也要有所涉猎。
  • 公司带给个人的影响是很大的,如果一个公司不愿意培养你,真的不值得去付出。
  • 沟通确实很重要,沟通不明确会导致接下来一系列的问题。
  • 说话是后天锻炼出来的,多和人交流,话到嘴边留三分。
  • 不用讨厌加班,人与人拉开差距就在下班后的几个小时,加班可以学习啊。雷军还说过你拿3000块钱换我一个月的青春,多不划算。

@junglehunter96
Copy link

junglehunter96 commented Jul 22, 2019

今天刷博客的时候看到一个题 :

异步的 Promise的 then 方法的回调是何时被添加到microtasks queue中的?

const pro = new Promise((resolve, reject) => {
    const pro1 = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(3);
        }, 0);
    });
    resolve(4);
    pro1.then((args) => {
        console.log(args);
    });
});
pro.then((args) => {
    console.log(args);
});

很多人都知道这道题的输出结果是4,3;但是我对题主的这个问题产生了很大的疑问,因为个人并没有着手实现过符合promise A/A+规划的promise,所以每次做这种题都是凭着平时的使用经验,实际上内心虚得很,然后自己查阅了 spec:ECMAScript 2018 Language Specification 根据 spec,如果调用 then 时 promise 是 pending 状态,回调会进入 promise 的 [[PromiseFulfill/RejectReactions]] 列表里;否则会进入 PromiseJobs;
PromiseJob 以及 Job Queue 是 ES 中的说法,而 macroTask 和 microTask 是浏览器中的概念,包括 setTimeout 也是宿主环境提供的。因此输出 4 3 是 ECMAScript 和 浏览器两种规范共同约束的结果。PromiseJob 对应浏览器中的一个 microTask.对于调用 then 时 promise 处于 pending 状态,回调函数进入到对应的 reactions 队列中。当该 promise 被 fulfill 或 reject 时,则 flush 对应的 reactions 队列 ,其中的每个 reaction 对应一个 PromiseJob 被按序 enqueue 到 Job Queue如果调用 then 时 promise 处于其他两个状态,Js 引擎就直接 enqueue 一个对应的 PromiseJob 到 Job Queue示例中的代码,在浏览器中如下顺序

0. current cycle of evevt loop start
1. Install Timer,Timer get enqueued
2. Resovle pro, because there is no fulfillReaction binding to pro, do nothing
3. call then() at pro1, because pro1 is pending, add fulfillReaction to pro1
4. call then() at pro, because pro is reolved,immediately enqueue a PromiseJob
5. current macroTask is finished
6. run all PromiseJobs(microTasks) in order, 
7. console.log(4)
8. current cycle of event loop is finishedanother cycle starts
9. Timer Fires, and pro1 is resolved
10. at this time, pro1 hasfulfillReactions,enqueue every fulfillReaction as a PromiseJob in order
11. current macro Job is finished 
12. run all PromiseJobs in order
13. console.log(3)
14. current cycle of event loop is finished

@fee-pg
Copy link

fee-pg commented Jul 22, 2019

2019/07/22

git更新远程仓库分支列表

git remote update origin --prune

取消/重置 git ssh 私钥密码

// 找到.ssh所在的文件夹,命令行执行
ssh-keygen -f id_rsa -p

@lczc
Copy link

lczc commented Jul 23, 2019

移动端打开指定App或者下载App

navToDownApp() {
      let u = navigator.userAgent
      if (/MicroMessenger/gi.test(u)) {
        // 如果是微信客户端打开,引导用户在浏览器中打开
        alert('请在浏览器中打开')
      }
      if (u.indexOf('Android') > -1 || u.indexOf('Linux') > -1) {
        // Android
        if (this.openApp('en://startapp')) {
          this.openApp('en://startapp') // 通过Scheme协议打开指定APP
        } else {
          //跳转Android下载地址
        }
      } else if (u.indexOf('iPhone') > -1) {
        if (this.openApp('ios--scheme')) {
          this.openApp('ios--scheme') // 通过Scheme协议打开指定APP
        } else {
          // 跳转IOS下载地址
        }
      }
    },
    openApp(src) {
      // 通过iframe的方式试图打开APP,如果能正常打开,会直接切换到APP,并自动阻止a标签的默认行为
      // 否则打开a标签的href链接
      let ifr = document.createElement('iframe')
      ifr.src = src
      ifr.style.display = 'none'
      document.body.appendChild(ifr)
      window.setTimeout(function() {
        // 打开App后移出这个iframe
        document.body.removeChild(ifr)
      }, 2000)
    }
欢迎一起讨论,如果有更好的写法欢迎指教

@yanghuiqi
Copy link

@lczc 这个前提是 达到腾讯的相应目标(唤起APP能力),才能唤起把。

@ihupoo
Copy link

ihupoo commented Jul 23, 2019

浏览器原生拖拽的元素超过300px会自动加上半透明效果

@xuhongbo
Copy link

lsof -i tcp:8080

mac环境下,命令行杀死特定node服务

由于在前端开发的时候,几个项目来回切换,难免会有端口占用的情况,之前的做法都是手动查找,由于比较麻烦,所以自己搞了个命令,一行搞定
lsof -i tcp:8080 | grep LISTEN | awk '{print $2}'| awk -F"/" '{ print $1 }' | xargs kill -9
上面举例的是杀死 8080 端口,有更好的方式,欢迎讨论

@xuhongbo awk -F"/" '{ print $1 }' 这部分命令解释一下,没懂

这个是取斜杠之前的数字部分,由于linux中的PID带有斜杠,习惯性写了个这个过滤,可以忽略

@xuhongbo
Copy link

mac环境下,命令行杀死特定node服务

由于在前端开发的时候,几个项目来回切换,难免会有端口占用的情况,之前的做法都是手动查找,由于比较麻烦,所以自己搞了个命令,一行搞定
lsof -i tcp:8080 | grep LISTEN | awk '{print $2}'| awk -F"/" '{ print $1 }' | xargs kill -9
上面举例的是杀死 8080 端口,有更好的方式,欢迎讨论

我都是全杀 killall node

现在vscode这些服务也是node启动的,还有钉钉,真的这样做没有问题吗???

@double306
Copy link

double306 commented Jul 23, 2019

将svg保存成图片到本地(问题:需要执行两次保存才会得到完整图片,求探讨!)

补充:可以随便找个svg代码,放在id为svg-wrap2的div下即可
//页面代码如下,
<div id="svg-wrap2"> <svg x="0" y="0" width="60" height="55.731074063951" class="imagesvg-svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 109.77 101.96"><defs><linearGradient id="a83ddb143-a16b-48c9-8eb2-539b2613fc51" x1="19.56" y1="12.32" x2="87.44" y2="80.2" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#ffb2c2"/><stop offset="1" stop-color="#f85e8a"/></linearGradient></defs><g style="isolation:isolate"><g><path d="M45.24 21c-7.61-6.82-22.43-.6-13.94 11.83S45.57 48.73 46.59 51c1.76 3.85 0 22.46 11.52 28.18 9.2 4.56 13.47-4.89 12.14-9.23-1.68-5.54-3.64-14.95-1.82-19.42 1.22-3 13.68-15.13 20-19.26 4.79-3.1 13.94-7.88 15.46 9.7S92.88 80.68 74.08 89.63s-53.6 2.3-66.39-35.58C-5.53 14.9 38.31-1 59.38.05 74 .76 80.67 5.81 76.58 15.66S62.38 34 59.66 34s-6.96-6.36-14.42-13z" fill="url(#a83ddb143-a16b-48c9-8eb2-539b2613fc51)"/><path d="M25.81 8.67c-8.34.48-15.72 3.18-20.28 10.09C-2.51 30.94.26 43.9 8 55l-.33-.94C.18 31.79 11.11 17.05 25.81 8.67z" fill="#f757af" style="mix-blend-mode:multiply"/><path d="M67.84 78.19c-2.07 2.12-5.34 3.14-9.73 1C46.56 73.43 48.35 54.82 46.59 51c-1-2.24-6.8-5.75-15.29-18.18S37.63 14.14 45.24 21s11.65 13 14.42 13 12.46-8.2 16.69-17.82C70.78 18.9 45.6 7.53 25.81 8.67 11.11 17.05.18 31.79 7.69 54.05L8 55c15.37 21.91 50.26 36.48 59.84 23.19z" fill="#f757af" style="mix-blend-mode:multiply"/><path d="M21.78 77.87a40.73 40.73 0 0 0 11.37 16.81c13.9 12 27.2 7.72 33.88-2.62-13.63 3.2-31.73-.28-45.25-14.19z" fill="#ab8eeb" style="mix-blend-mode:multiply"/><path d="M70.4 70.55c.78 4.55-3.51 13-12.29 8.6C46.56 73.43 48.35 54.82 46.59 51c-1-2.24-6.8-5.75-15.29-18.18-5.25-7.69-1.58-13 3.78-14.32-11.65 1.06-22.59 34.4-13.3 59.4C35.3 91.78 53.4 95.26 67 92.06a27.87 27.87 0 0 0 3.4-21.51z" fill="#ab8eeb" style="mix-blend-mode:multiply"/><path d="M102 56.74c4.71-5.86 7.76-11.65 7.8-15.82 0-4.43-3.11-7.51-7.85-8.64a25 25 0 0 1 2 8.69A41.34 41.34 0 0 1 102 56.74z" fill="#ffbd88" style="mix-blend-mode:multiply"/><path d="M68.43 50.53c-1.82 4.47.14 13.88 1.82 19.39 1.33 4.34-2.94 13.79-12.14 9.23a13.92 13.92 0 0 1-3.46-2.42c11.09 11.36 34.94-4.58 47.31-20a41.34 41.34 0 0 0 2-15.77 25 25 0 0 0-2-8.69c-6.53-1.54-16.06.62-24.39 8.09-.76.73-1.51 1.45-2.23 2.16C71.78 46 69 49.2 68.43 50.53z" fill="#ffbd88" style="mix-blend-mode:multiply"/><path d="M86.62 17.85C84.08 15.2 98.57-3.86 104.24 2S89.15 20.49 86.62 17.85zM7 57.34c.3-1.92-6-4.54-6.69-.27s6.4 2.19 6.69.27z" fill="#f757af"/><path d="M93.51 22.93c-3.38-2.34 6.86-7.3 8.76-3.49s-6.6 4.98-8.76 3.49zM70.94 93.17c3.66 0 2.58 4.87-.61 3-1.82-.99-1.43-3.01.61-3z" fill="#ab8eeb" style="mix-blend-mode:multiply"/><path d="M8 60.94c-2.06-.43-6.06.3-7.63 2.66-1.37 2 1.47 7.86 7 1.4 3.16-3.69 1.57-3.85.63-4.06z" fill="#ffbd88" style="mix-blend-mode:multiply"/></g></g></svg> </div>
<script type="text/javascript">
var svgXml2 = document.getElementById('svg-wrap2').innerHTML;

	var image1 = new Image();
	image1.src = 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(svgXml2))); //给图片对象写入base64编码的svg流

	var canvas2 = document.createElement('canvas');  //准备空画布
	canvas2.width = document.getElementsByTagName('svg')[1].width['animVal'].value;
	canvas2.height = document.getElementsByTagName('svg')[1].height['animVal'].value;

	var context1 = canvas2.getContext('2d');  //取得画布的2d绘图上下文
	context1.drawImage(image1, 0, 0);

	//图片导出为 png 格式
	var type = 'png';
	var imgData = canvas2.toDataURL(type);
	/**
	 * 获取mimeType
	 * @param  {String} type the old mime-type
	 * @return the new mime-type
	*/
	var _fixType = function(type) {
	   type = type.toLowerCase().replace(/jpg/i, 'jpeg');
	   var r = type.match(/png|jpeg|bmp|gif/)[0];
	   return 'image/' + r;
	}; 

	// 加工image data,替换mime type
	imgData = imgData.replace(_fixType(type),'image/octet-stream');
	console.log(imgData);

	/**
	 * 在本地进行文件保存
	 * @param  {String} data     要保存到本地的图片数据
	 * @param  {String} filename 文件名
	 */
	var saveFile = function(data, filename){
	    var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
	    save_link.href = data;
	    save_link.download = filename;

	    var event = document.createEvent('MouseEvents');
	    event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
	    save_link.dispatchEvent(event);
	};

	// 下载后的文件名
	var filename = '二维码 .' + type;
	// download
	saveFile(imgData,filename);
</script>

@lczc
Copy link

lczc commented Jul 23, 2019

@yanghuiqi
如果在微信浏览器中是无法唤醒App的,因为微信对所有的分享链接接做了scheme屏蔽,也就是说分享连接中所有对于scheme的调用都被微信封掉了,所以我们提示用户尝试在浏览器打开,浏览器也是不能够判读用户是否安装了某个App的,只能尝试打开,打不开就去下载。有些app是能在微信打开是因为微信有一个白名单(有关系就是不错),对于在白名单中的分享链接是不会屏蔽掉scheme调用的,所以能打开。

@KRISACHAN
Copy link

2019年7月23日份学习

同步阻塞法实现sleep函数

const sleep = delay => {
	const start = new Date().getTime();
	while (new Date().getTime() < start + delay) {
		continue;
	};
};
console.log(1);
sleep(3000);
console.log(2);

@Yangfan2016
Copy link

20190723

利用 a 标签解析 URL

function parseURL(url) {
    var a =  document.createElement('a');
    a.href = url;
    return {
        host: a.hostname,
        port: a.port,
        query: a.search,
        params: (function(){
            var ret = {},
                seg = a.search.replace(/^\?/,'').split('&'),
                len = seg.length, i = 0, s;
            for (;i<len;i++) {
                if (!seg[i]) { continue; }
                s = seg[i].split('=');
                ret[s[0]] = s[1];
            }
            return ret;
        })(),
        hash: a.hash.replace('#','')
    };
}

@cyhwinner
Copy link

websocket实战运用中, 在与后台连接中,会发现有两个问题点。第一个在谷歌浏览器下会报错

Error during WebSocket handshake: Incorrect 'Sec-WebSocket-Accept' header value

而在safari浏览器下报错

 Error during WebSocket handshake: Sec-WebSocket-Accept mismatch

两个报错原因是相同的,是因为后台返回的Sec-WebSocket-Accept 和 给前端发送的头部Sec-WebSocket-Key算出的结果不一致。这时候可以让后台手动添加这个头部值,这样一来每一次计算的值必定是会正确的。具体为什么有时候后台框架计算有时候正确有时候错误,这个就不得知了。
还有一个问题点是在于,在两者没有消息通信的时候,会隔一段时间,websocket会被自动断开。原因在于,中间代理的nginx在没有发生通信的时候,会隔一定时间就会断开连接不再进行代理。所以可以采用心跳法来保持连接,通俗的说就是隔一段时间发一次消息给后台,让nginx保持连接。还有一种方式就是在即将断开连接,也就是websocket中的onclose回调中,重新再调用一次websocket连接

@shfshanyue
Copy link

图片懒加载

<ul>
	<li><img src="./img/default.png" data="./img/1.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/2.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/3.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/4.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/5.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/6.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/7.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/8.png" alt=""></li>
</ul>
let imgs =  document.querySelectorAll('img')
// 窗口可视区高度
let clientHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
// img 距离窗口可视区顶部的距离 imgs[i].getBoundingClientRect().top
function lazyLoadImg () {
    for (let i = 0; i < imgs.length; i ++) {
        if((imgs[i].getBoundingClientRect().top + imgs[i].height)>=0&&imgs[i].getBoundingClientRect().top < clientHeight ){
            imgs[i].src = imgs[i].getAttribute('data')
        }
    }      
}
window.addEventListener('scroll', lazyLoadImg);

可以使用最新的 API https://developer.mozilla.org/zh-CN/docs/Web/API/Intersection_Observer_API 来做这件事,会更简单而且可控一些

@Yangfan2016
Copy link

Yangfan2016 commented Jul 24, 2019

20190724

解决Vuex状态丢失的问题

原文
npm
在线例子

  • 默认存储到localStorage
import createPersistedState from "vuex-persistedstate"
const store = new Vuex.Store({
  // ...
  plugins: [createPersistedState()]
})
  • 想要存储到sessionStorage,配置如下
import createPersistedState from "vuex-persistedstate"
const store = new Vuex.Store({
  // ...
  plugins: [createPersistedState({
      storage: window.sessionStorage
  })]
})

@KieSun
Copy link
Owner Author

KieSun commented Jul 24, 2019

如何优雅的用js写一个最简单的商品星级评价:"★★★★★☆☆☆☆☆"
例如后台返回是1 则展示1个有颜色的星星 4个空星星
返回2则展示2个有颜色的星星 3个空的空星星

"★★★★★☆☆☆☆☆".slice(5 - rate, 10 - rate);rate为星级1-5

欢迎一起讨论,如果有更好的写法欢迎指教

简单是简单的了,但是在真实需求下这种方法基本是用不了。

不说如何展示半颗星,即使是星星的样式就不大好把控。

当然还是很感谢分享内容!

@mengsixing
Copy link

20190724

学习希尔排序

希尔排序使用算法中的分治思想,先把需要排序的数组拆分成 n 个小数组,在 n 个小数组中分别进行插入排序,然后将排序好的小数组再组合起来。

插入排序在处理小数据或者基本有序数据时,效率很高。希尔排序将数据拆分成小数据,并分别排序,就能大大提高插入排序的效率,可以说是插入排序的升级版。

function shellSort(array) {
  // 定义间隔序列,这里写死了,可以动态定义
  const gaps = [5, 3, 1];
  for (let index = 0; index < gaps.length; index++) {
    const gap = gaps[index];

    for (let outer = gap; outer < array.length; outer++) {
      // 检查的数字
      const temp = array[outer];
      for (
        let inner = outer - gap;
        // 如果比之前的 gap 小,就交换一下,直到交换到第一个 gap 处
        inner >= 0 && array[inner] > temp;
        inner -= gap
      ) {
        swap(array, inner, inner + gap);
      }
    }
  }
  return array;
}

@kdush
Copy link

kdush commented Jul 25, 2019

内网环境 如何使用gitKraken

@Geek-James
Copy link

阅读了jQuery源码-延迟函数的解决方案,并且写了学习笔记 https://github.com/Geek-James/Blog

@HEternally
Copy link

20190723
发布个人第一个npm包
介绍
基于人像区域的蒙版(mask)图层的人像抠出方法,即将人和背景进行分离
npm
Github

@KieSun
Copy link
Owner Author

KieSun commented Jul 25, 2019

内网环境 如何使用gitKraken

可以参考下别人的格式,写一下学到的内容。

@KieSun
Copy link
Owner Author

KieSun commented Jul 25, 2019

正在学习node,没有用框架,做了两个事。
1.用node建立了一个服务端,接收post图片并压缩。
2.用node爬了nba官网的信息,将内容作为邮件发送给自己。
还有就是希望大家给点学习nodejs的建议

可以参考下别人的格式,写一下学到的内容。

@Geek-James
Copy link

阅读了jQuery源码-延迟函数的解决方案,并且写了学习笔记 https://github.com/Geek-James/Blog

jQuery源码 - Callbacks原理分析及实现
jQuery源码 - Deferred异步回调原理分析及实现

@teachat8
Copy link

2019年7月25日份学习

vscode内存占用过高解决方法?

文件>首选项>设置, 搜索设置 "search.followSymlinks" :false;

@TNTrocket
Copy link

2019.7.25

  • web打印
@media print {
.noPrint{
 display: none
}
}

可以css控制打印的样式

@lancelot-song
Copy link

分享些Flutter的相关吧:
Flutter的底层图像渲染引擎是基于C++开发的Skia,被Google收购后应用于Chrome、Android等核心产品上,目前Android系统都内置的有此技术,所以在打包方面,因IOS系统不支持Skia进行渲染,会配上此渲染引擎,所以打包时会比Android的包大一些,底层渲染能力达到一致了,就解决了平台不同渲染有差异的问题。
也因为Flutter的开发需要新的语言特性,若使用Javascript则需要经过漫长的W3C标准审批等流程,影响整体开发进度,故使用Dart作为Flutter的开发语言,也因为Dart是新语言,借鉴了多类语言的优点,并且Dart是自家产品,可以快速的进行迭代更新。
Flutter的绘制顺序是按照深度遍历进行渲染,并优先渲染父节点,再渲染子节点,若其中一个节点改变了渲染,则会将所有图层一起计算出和最终效果后交由Skia来做处理,而不是单独渲染,影响渲染性能。

在windows环境编写Flutter的时候可以安装Android Studio/VScode来开发,但都要安装插件来支持Flutter的语法,其中AndroidStudio内置的有android模拟器,提供便捷的测试效果,所以Anrdoid Studio是必装的

至于Dart语法相关知识我还没学透,说不了太多,但聊胜于无,它和JavaScript类似的点有:
class Child extends Parent 继承父类;
类似的运算符:
a?.print() : a为null则不调用自身或父类继承的print方法,防止发生意外的错误调用
a ??= b :a为null 则赋值为b
a ?? b : a存在返回a 否则返回b 相当于a ? a : b

TS语法:
class Child implements Parent 实现抽象父类

Dart语法也就是所谓的集百家之所长,很多语言的优点特性都引入了进来,光凭借JavaScript的编写思想是无法运用好它的,需要学习其他语言的优势思想与语法糖,这也是极好的。

@HEternally
Copy link

20190725
Promise相关知识:
1、then方法提供一个自定义的回调函数,若传入非函数,则会忽略当前then方法。
2、回调函数中会把上一个then中返回的值当做参数值供当前then方法调用。
3、then方法执行完毕后需要返回一个新的值给下一个then调用(没有返回值默认使用undefined)。
4、每个then只可能使用前一个then的返回值。

@qifengwangye
Copy link

偶然看到一种之前没有想到过的数组去重方法:

  var array = [1, 2, 1, 1, '1'];
  function unique(array) {
    var obj = {};
    return array.filter(function(item, index, array){
      return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
    })
  }
  • 利用一个空的 Object 对象,我们把数组的值存成 Object 的 key 值,比如 Object[value1] = true,在判断另一个值的时候,如果 Object[value2]存在的话,就说明该值是重复的。因为 1 和 '1' 是不同的,但是这种方法会判断为同一个值,这是因为对象的键值只能是字符串,所以我们可以使用 typeof item + item 拼成字符串作为 key 值来避免这个问题

@kdush
Copy link

kdush commented Jul 25, 2019 via email

@Mikerui
Copy link

Mikerui commented Jul 26, 2019

退出微信网页窗口的方法,ios和Android都有的
setTimeout(function() { document.addEventListener( 'WeixinJSBridgeReady', function() { WeixinJSBridge.call('closeWindow'); }, false ); // 关闭iPhone WeixinJSBridge.call('closeWindow'); }, 300);

@jialudev
Copy link

Math.trunc(13.37) // 13

...没有进位有啥用。。

@mengsixing
Copy link

20190726

学习归并排序

归并排序使用算法中的分治思想,将一个大数组拆分成 2 个小数组,直到最后拆分为 1 个元素的数组,最后再将每个小数组按顺序合并成大数组。

将二个有序数组合并也十分简单,只需要从二个数组的第一个数开始比较,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数组为空,那直接将另一个数组的数据依次取出即可。

归并排序的效率是比较高的,设数列长为 N,将数列分开成小数列一共要 logN 步,每步都是一个合并有序数列的过程,时间复杂度可以记为 O(N),故一共为 O(N*logN)。

// 归并排序算法
function mergeSort(array) {
  // 避免污染传入的数组
  const temp = [...array];
  splitArray(temp, 0, array.length - 1);
  return temp;
}

// 将大数组拆分成两个小数组
function splitArray(array, start, end) {
  if (start < end) {
    const mid = Math.floor((start + end) / 2);
    splitArray(array, 0, mid);
    splitArray(array, mid + 1, end);
    mergeArray(array, start, mid, end);
  }
}

// 合并两个排序好的数组
function mergeArray(array, start, mid, end) {
  var i = start;
  var j = mid + 1;
  var k = 0;
  var temp = [];
  while (i <= mid && j <= end) {
    if (array[i] <= array[j]) {
      temp[k] = array[i];
      i++;
    } else {
      temp[k] = array[j];
      j++;
    }
    k++;
  }

  while (i <= mid) {
    temp[k] = array[i];
    i++;
    k++;
  }

  while (j <= end) {
    temp[k] = array[j];
    j++;
    k++;
  }

  for (let index = 0; index < k; index++) {
    array[index + start] = temp[index];
  }
}

var array = [4, 3, 1, 9, 6, 2, 7, 8, 5];
console.warn('归并排序', mergeSort(array));

@KRISACHAN KRISACHAN mentioned this issue Jul 26, 2019
@KRISACHAN
Copy link

Math.trunc(13.37) // 13

...没有进位有啥用。。

不知道啊,有这个API,应该有它的用处吧

@yes1am
Copy link

yes1am commented Jul 27, 2019

2019-07-27

JS 函数对象参数的陷阱

1. 正文

上周在实现某个弹层功能的时候,用到了rc-util里的 contains 方法函数, 结果 code-review 的时候同事对该代码提出了疑问:

rc-util 源码仓库

export default function contains(root, n) {
  let node = n;
  while (node) {
    if (node === root) {
      return true;
    }
    node = node.parentNode;
  }
  return false;
}

上述代码是 antd 内部抽象的一个工具方法,用来判断某个dom是否为另一个dom的祖先节点。

同事疑问的是 let node = n; 这段代码是不是多余的?

首先一开始的理解是 函数参数 n 是一个对象,一个dom节点对象。
如果用 node 保存 n 的值,防止 node = node.parentNode 这段代码执行的时候,会改变传入的实参 n 对应的值。

毕竟以下的代码我们都很熟悉:

function contains(root, n) {
  if(n) {
    n.a = 3
  }
}

const A = {a:1};
const B = {a:2};
contains(A,B)
console.log(B)    // {a:3}

即当实参为对象时,函数内部是可以改变该对象的值从而影响函数之外的实参。

但是测试另外一段代码,发现和理解的不一样:

function contains(root, n) {
  if(n) {
    n = {a:3}
  }
}

const A = {a:1};
const B = {a:2}
contains(A,B)
console.log(B) // {a:2}

n.a = 3n = {a:3} 这两段代码是不一样的。

网上也有相关资料,其实可以简单的理解为: 当函数一开始执行时,n 是指向实参 B 的一个引用.

n.a = 3 是在引用上关联了一个属性,此时和 B 还是同一个引用,因此会改变实参B的值。

n = {a:3} 则使得 n 不再指向实参 B, 而是指向一个新对象{a:3},也就是 nB 彻底断绝了关系,因此不会改变实参 B 的值。

是不是可以给蚂蚁的团队提个issue建议删除该代码,不过有这句代码也不会有什么bug~

2. 相关资料

JavaScript深入之参数按值传递

@ABasket
Copy link

ABasket commented Jul 27, 2019

2019-07-27

开始学习数据结构与算法 Java版

  1. 算法的评估
  2. 时间复杂度的估算
  3. 大O表示法
  4. 裴波那契数列复杂度分析

共用时2个小时,视频+思考+敲代码

裴波那契数列

// 裴波那契数列指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、……
// value = 前两个数的和 表达式F(n)=F(n-1)+F(n-2)
// 算法1
public static long fib(long n) {
		if(n <= 1) return n;  // 执行1+1=2次数  n <= 1 一次 return n 一次
		return fib(n-1)+fib(n-2); // 0.5*2^n次
}
// 算法2
public static long fib(long n) {
		if(n <= 1) return n;       // 2
		long first = 0;            // 1
		long second = 1;         //  1
		for (long i = 0; i < n - 1; i++) {  // n 
			long sum = first + second;      // n
			first = second;                 // n
			second = sum;                  // n
		}
		
		return second;                     // 1
}
/*

(1)阵列元素相加为2n+3 = O(n)

(2)矩阵相加为2n^2+2n+1 = O(n^2)

(3)矩阵相乘为2n^3+4n^2+2n+2 = O(n^3)

 (4) 执行次数为常数  2 = O(1)
算法2的时间复杂度是O(n) 
 2+1+1+4n+1 = 4n+5  取最高阶  n  O(n)
算法1的时间复杂度是O(2^n)
比如:fib(5)
   图1
 可以看到fib(5) , 第一行是1个,第二行是2个(fib(4) 和 fib(3)), 第三行是 4个(fib(3),fib(2),fib(2),fib(1)) , 第四行是 6个。第五行 2个。
	1 + 2 + 4 + 8 
	= 2 ^0 + 2 ^ 1 + 2^2 + 2^3
	= 2^4 - 1
	= 2^(n - 1) - 1
	 = 0.5 * 2^n
所以时间复杂度是 O(2^n)
链接:https://blog.csdn.net/M316625387/article/details/89467298

*/

��������述

​ (图1)csdn博客

@KieSun
Copy link
Owner Author

KieSun commented Jul 28, 2019

2019/07/22

01 graphql 中多级分页查询时的 N+1 问题

此处只能在客户端避免多层分页查询,而当有恶意查询时会加大服务器压力。可以使用 Hash Query 避免此类问题,避免暴露原始 Query,同时也在生产环境禁掉 introspection

{
  users (page: 1, pageSize: 3) {
    id
    todos (page: 1, pageSize: 3) {
      id 
      name
    } 
  }
}
select id from users limit 3

select id, name from todo where user_id = 1 limit 3
select id, name from todo where user_id = 2 limit 3
select id, name from todo where user_id = 3 limit 3

记录

02 在前端中把 gql 统一管理减小打包体积

准确说,已经把 gql 统一管理为 query.gql,通过 loader 引入,会被打入 common.js
而在个别页面又单独通过 graphql-tag 引入,被按需加载打包,而此时 graphql-tag 又依赖 graphql,gql 统一管理后,此时的两个模块的依赖也就没有了。

通过 webpack 分析,gzip 后的总体积变化: 191.64KB -> 176.51KB,体积缩减还是比较可观的。

优化记录

03 获取当前 commit hash

可以通过 npm scripts 注入到项目中,方便集成到 sentrylogger 等工具组件中

git rev-parse --verify HEAD  | cut -c 1-8

后来找到更简单的命令 git rev-parse --short HEAD

2019/07/23

01 本地更好的流式日志格式化

服务器端的日志很重要,一般设置为 jsonl 格式,方便在 elk 上查询或者使用 spark 分析。而在本地调试时就不是很直观了,而日志又是 stream 的数据。此时可以使用 jq 对日志进行美化

# 实时查看日志,并且只关注 message 字段
tail -f logs/db.log | jq '{message}'

此时你不仅有了更好的可视化,而且只需要关注你自己关心的字段就可以了,体验很棒

02 Intersection Observel 做路由页面预加载与图片懒加载

由于我的网站使用了 next.js 的技术栈,最近对 next 升级到了 v9,对 next 一直有所关注。在今天读了 Next.9 features,其中有一个点:

Next.js 9 will automatically prefetch components as they appear in-viewport.

其中原理便是使用 Intersection Observel 来监听元素是否出现在当前可视窗口内。 Next.js 可以对新的页面资源做懒加载,举一反三,我们也可以使用它对图片做懒加载。

03 了解一个 APP 从开发到盈利所经历的事

2019/07/24

01 在 React 中使用 React.Fragment 或者 <></> 包含多个子元素

恩,这个是查看某项目代码时看到的,虽然一直知道了 react 目前已经可以包含多元素,但也没有细究,今天偶然得知,受用很多。

(
  <>
    <td>Hello</td>
    <td>World</td>
  </>
);

02 sar (System Activity Monitor)

sarvmstatiostat 相比,不仅可以实时监控 linux 系统 IO/memory/cpu 等的信息,而且可以 获取一段时间内的系统统计信息,比如他可以获取一天时间内的 CPU 使用率。我也把它记录在了我的博客里

linux 指标监控

03 Apollo Federation & GraphQL Gateway

简而言之,Apollon Federation 可以把多个 graphql service 组合成一个 API Gateway。如果公司的所有业务与微服务都使用了 GraphQL,则它正好可以做一个不错的服务整合,这还挺令人兴奋的。

2019/07/25

总结了LF 与 CRLF 的一篇文章

了解一些底层知识,视野会开阔很多。如本篇文章可以通过系统调用来看换行符到底是什么。

用户增长模型 RARRA

我的理解,用户留存比较重要,应作为着力点

2019/07/26

了解 vuepress 如何写插件,并给我的博客写了一个归档的插件

https://github.com/shfshanyue/blog/blob/master/.vuepress/config.js

2019/07/27

尝试使用 netlify 新建了我的博客

博客地址 https://shanyue.netlify.com/

至于我现在的博客还是使用 hugo 构建,不得不说 hugo 的构建速度真是很快。另外使用自建的 gitlab,gitlab-ci,docker-compose 来做自动部署,不得不说运维这些还是有些成本的。而 netlify 就简单很多了,这些运维工作都不需要你来关心。

云是一种趋势,以后考虑能够 SAAS 化的服务全部 SAAS 化。

graphql-code-generator 自动为前端生成 graphql schema 相对应的 ts 的 type

毫无疑问,前端不用手动配置关于接口的 interface,大大解放了前端的生产力,而且减少了失误率。

大佬每天都记录了学习的内容,真的很棒!

@RuinousCheng
Copy link

Math.trunc(13.37) // 13

...没有进位有啥用。。

不知道啊,有这个API,应该有它的用处吧

要进位的话就用Math.round(), 这个就是用来去除小数部分的,还会隐式把参数转为数字。

@luohong123
Copy link

luohong123 commented Jul 28, 2019

20190728 study

mkdir qingcheng
npm init 
npm login
npm publish --access=public // 设置 --access=public才能发布@开头的包

首先执行下 npm adduser ,输入相应的 Username 、 Password 、 Email。
中途遇到一个问题,没有发布成功,是镜像的原因,
Logged in as 您的Username on https://registry.npmjs.org/. 如果 on 后面不是 https://registry.npmjs.org/ ,而是其他的镜像,比如我们大家常见的淘宝镜像:
http://registry.npm.taobao.org/ 那么首先替换成原来的,替换成原来执行如下命令:
npm config set registry https://registry.npmjs.org/ 最后,替换完毕再执行 npm adduser 、 npm publish

@lllllllqw
Copy link

2019-07-27

JS 函数对象参数的_陷阱_

1. 正文

上周在实现某个弹层功能的时候,用到了rc-util里的 contains 方法函数, 结果 code-review 的时候同事对该代码提出了疑问:

rc-util 源码仓库

export default function contains(root, n) {
  let node = n;
  while (node) {
    if (node === root) {
      return true;
    }
    node = node.parentNode;
  }
  return false;
}

上述代码是 antd 内部抽象的一个工具方法,用来判断某个dom是否为另一个dom的祖先节点。

同事疑问的是 let node = n; 这段代码是不是多余的?

首先一开始的理解是 函数参数 n 是一个对象,一个dom节点对象。
如果用 node 保存 n 的值,防止 node = node.parentNode 这段代码执行的时候,会改变传入的实参 n 对应的值。

毕竟以下的代码我们都很熟悉:

function contains(root, n) {
  if(n) {
    n.a = 3
  }
}

const A = {a:1};
const B = {a:2};
contains(A,B)
console.log(B)    // {a:3}

即当实参为对象时,函数内部是可以改变该对象的值从而影响函数之外的实参。

但是测试另外一段代码,发现和理解的不一样:

function contains(root, n) {
  if(n) {
    n = {a:3}
  }
}

const A = {a:1};
const B = {a:2}
contains(A,B)
console.log(B) // {a:2}

n.a = 3n = {a:3} 这两段代码是不一样的。

网上也有相关资料,其实可以简单的理解为: 当函数一开始执行时,n 是指向实参 B 的一个引用.

n.a = 3 是在引用上关联了一个属性,此时和 B 还是同一个引用,因此会改变实参B的值。

n = {a:3} 则使得 n 不再指向实参 B, 而是指向一个新对象{a:3},也就是 nB 彻底断绝了关系,因此不会改变实参 B 的值。

是不是可以给蚂蚁的团队提个issue建议删除该代码,不过有这句代码也不会有什么bug~

2. 相关资料

JavaScript深入之参数按值传递

分析思路没啥问题, 不过这么做的真正原因其实是因为一条规则: 不对函数的参数进行赋值, 规则见 eslint

@yes1am
Copy link

yes1am commented Aug 2, 2019

@lllllllqw
学习了,原来是这样, 看了下utils 最终是基于 airbnb做的eslint规范,确实 airbnb规范存在这条规则。

@13168335674
Copy link

移动端打开指定App或者下载App

navToDownApp() {
      let u = navigator.userAgent
      if (/MicroMessenger/gi.test(u)) {
        // 如果是微信客户端打开,引导用户在浏览器中打开
        alert('请在浏览器中打开')
      }
      if (u.indexOf('Android') > -1 || u.indexOf('Linux') > -1) {
        // Android
        if (this.openApp('en://startapp')) {
          this.openApp('en://startapp') // 通过Scheme协议打开指定APP
        } else {
          //跳转Android下载地址
        }
      } else if (u.indexOf('iPhone') > -1) {
        if (this.openApp('ios--scheme')) {
          this.openApp('ios--scheme') // 通过Scheme协议打开指定APP
        } else {
          // 跳转IOS下载地址
        }
      }
    },
    openApp(src) {
      // 通过iframe的方式试图打开APP,如果能正常打开,会直接切换到APP,并自动阻止a标签的默认行为
      // 否则打开a标签的href链接
      let ifr = document.createElement('iframe')
      ifr.src = src
      ifr.style.display = 'none'
      document.body.appendChild(ifr)
      window.setTimeout(function() {
        // 打开App后移出这个iframe
        document.body.removeChild(ifr)
      }, 2000)
    }
欢迎一起讨论,如果有更好的写法欢迎指教

😁推荐个库 callapp-lib

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests