Secbone 发布的文章

小问题,简单记一下

今天用 marquee 标签做滚动的时候,在 Chrome 下看效果没有问题,但是后来发现在手机微信上,每当内容滚动过 marquee 宽度的距离以后,就会重置重新从头滚动,这一点让我着实蛋疼了一下。。。。

然后后来排查的时候发现,是因为我在样式里给 marquee 设置了宽度(因为不想整个屏幕宽度滚动,所以就设置了一下宽度),然后就出现了问题,这个宽度被继承到 marquee 里面的滚动块上了,所以导致当滚动过这个距离以后,marquee 会以为滚动内容结束了,从而又重新滚动。

那么,当我们确实需要改变 marquee 的宽度的时候怎么办呢?

哈哈,给它外面加上一个 div,然后给 div 指定宽度就可以了

<style>
#marquee{
    width: 300px;
    ...
}
</style>
<div id="marquee">
    <marquee behavior="scroll" direction="left">
        我是内容我是内容我是内容我是内容
    </marquee>
</div>

嗯嗯,大概就是这样啦~

--------- 分割线诈尸 -----------

目前微信已经更新了 X5 内核的版本,已经不再支持 <marquee> 标签,所以做这种滚动的效果还是使用 Animation 来做喽~

是的,我又用上 sass 了,新公司在用,所以就又写 sass 了。

然后今天遇到的小问题,随手记一下

当我们用 sass 写如下代码的时候

.class{
    $padding: 5px;
    width: calc(100% - $paddding * 2);
}

嗯嗯,看上去好像很正常。。。

错!! 编译完了之后,你会发现这段代码是这样的

.class{
    width: calc(100% - $padding * 2);
}

然后浏览器就无情的忽略掉这一行谜一样的样式了

这尼玛是什么呀?! 摔!

好吧,看样子 sass 在编译的时候,把括号里面的变量当做字符串处理了。 所以我们该怎么办呢?

哈哈哈,对!还记得 sass 怎么在字符串里拼接变量么? 就是它!

.class{
    $padding: 5px;
    width: calc(100% - #{$paddding * 2});
}

OK,解决!

事件起因源于对我之前写的一个小工具的再优化,工具遇到的场景大概是这样的:

工具需要在用户点击完按钮后做大量的循环操作(这里暂时没有算法层的优化),大概有 6 万次,然后与此同时,界面上还需要显示出当前循环进行的程度,百分比。大概是这样的:

setInterval(function() {
    // trigger progress...
}, 16);

for(var i=0; i<60000; i++) {
    // do something...
}

这里在之前就遇到一个问题,就是当 js 去在一个函数里进行循环操作时,js 会被卡住,因为是一个同步过程,所以界面的更新事件会在循环进行完以后再触发执行,这当然不是我们想要的。然后后来,我就把它变成了下面这种递归模式:

function loop() {
    // do something ...
    
    setTimeout(loop, 0);
}

这样的话,就把每次循环变成了一个异步事件,等上次循环执行完后,再把下次循环的事件挂到事件队列上,等待下次 event loop 执行。这样就使得界面更新事件可以正常在循环进行中的时候触发了。

然而这样又出现了另一个问题,就是循环执行速度极慢(详情可脑补《疯狂动物城》的树懒。。。)

好吧,其实分析一下就可以得知,当我执行完一次函数的时候,才把下次循环挂到事件队列上,也就是下次循环的执行时间最短是下次 event loop 取事件队列的间隔时间,所以就导致速度很慢。

OK,那我把所有循环都做成异步事件,一次性都挂到事件队列上呢?

for(var i=0; i<total; i++) {
    setTimeout((function(count){
        return function() {
            // do something...
        }
    })(i), 0);
}

然后呢?我得到的结果是并不能到达我们想象的样子。这些事件会被快速执行,但是界面更新事件只会触发一次,然后就等全部循环执行完成后再次触发,有点儿类似同步循环的阻塞,但是我试了一下,要比同步的阻塞写法慢一些。

好吧,其实这里想一些也就明白了,我这里是将所有的异步事件一次性挂到事件队列上面,导致这一次的事件队列特别长,所以 js 会等这一次的事件全部处理完成后,再去取下次的队列,也就变成了类似同步的写法,只是中间应该会耗费一些事件去切换事件处理吧。

那么再然后呢?怎么样才能做到既能快速进行运算,有不影响到其他事件的触发呢?

最后我试着把循环拆成了若干个小循环去完成,大概是这样:

function loop() {
    for(var i=current; i<total && i<current+200; i++) {
        // do something...
    }
    current = i;
    
    setTimeout(loop, 0);
}

这样就是每次异步函数只执行 200 次,然后把下次的循环挂到下次的事件队列里,这样界面更新事件就有机会出现在下次的事件队列中,从而得到触发。

事情就此解决,也从这件事情中,更明白了一些关于异步和 event loop 的东西:

  • 单个函数内部的执行是同步的,影响到后面函数的执行
  • js 会在全部执行完一次 event loop 的异步事件后,再去取下次的队列,也就是单次队列里面的异步函数如果耗费大量时间的话(不管是因为单个函数耗费大还是因为所有函数个数耗费大),都会影响到下次取队列的时间
  • js 是单线程的,即使你是异步写法,到后面也是同步执行,所以要更好的优化性能的话,就尽量的让 js 在每次的 event loop 的间隔时间里,尽可能多的进行运算。如果运算时间实在太长,就合理的拆成小段儿来填充进每一个 event loop 里面

最后这里记篇文章:

How JavaScript Timers Work
是安然君推荐给我的,把 event loop 的运行机制讲的很明白,个人感觉很好,有空儿尝试翻译一下~

嗯嗯,大概就是这样吧,本文其实少了很多图示,(好吧,其实是因为我太懒了。。。),大家可以去看推荐的文章,讲的很清楚。

本文中如果有不对的地方,欢迎指正,一起学习~

嗯嗯,就这样吧,晚安~

好吧,没啥,就是他们最近在迁移服务器的时候,安装 npm 包的时候又遇到 Please try running this command again as root/Administrator. 这个问题了,然后就准备把这个问题记一下,方便为遇到同样问题的同学参考吧

原文地址: https://docs.npmjs.com/getting-started/fixing-npm-permissions

当你安装一个包到全局的时候可能会遇到一个 EACCES 错误,这是因为你没有 npm 存储全局包的目录的写权限。

你可以通过两种途径来修复这个问题:

  1. 修改 npm 默认目录的权限
  2. 修改 npm 默认目录到其他目录

在进行一下操作之前,请先备份一下你的电脑

方法1:修改 npm 默认目录的权限

  1. 找到 npm 默认目录的路径
npm config get prefix

对于大多数的系统来说,应该是 /usr/local

注意: 如果你显示的路径是只是 /usr,请使用 方法2

  1. 修改 npm 目录所有者为当前用户
sudo chown -R $(whoami) $(npm config get prefix)/{lib/node_modules,bin,share}

这将修改所有被 npm 和其他工具(lib/node_modules, bin 和 share)使用的子目录的权限

方法2:修改 npm 默认目录到其他目录

有些时候你会因为某些问题不想修改 npm 目录(像:/usr)的所有关系,比如你在跟另外的用户共享系统的时候。

我们可以通过修改配置让 npm 使用一个不同目录来代替。在下面的例子里,我们使用了一个在我们 home 目录下的一个隐藏目录

  1. 创建一个用于安装全局包的目录
mkdir ~/.npm-global
  1. 配置 npm 使用新的目录路径
npm config set prefix '~/.npm-global'
  1. 打开或者创建一个 ~/.profile 文件并且添加一行
export PATH=~/.npm-global/bin:$PATH
  1. 回到命令行,更新系统变量
source ~/.profile

测试一下,不使用 sudo 下载一个包到全局

npm install -g jshint

你也可以使用环境变量来代替 2~4 步(当你不想更改 ~/.profile

NPM_CONFIG_PREFIX=~/.npm-global npm install -g jshint

OK, 就这样啦~ 希望会有帮助吧

在内网搞了个测试机,但是装 node 的时候提示 gcc 版本太低,要升级到 4.8 以上
好吧,那就升级呗~ 中间遇到好多蛋疼是事情,这篇就简单记一下升级过程,备忘,备忘~

先下载源码包~ http://ftp.gnu.org/gnu/gcc/

解压,进入文件夹,然后在下载编译所需要的依赖

cd gcc-4.8.2
./contrib/download_prerequisites

OK,编译安装~

configure --enable-checking=release --enable-languages=c,c++ --disable-multilib --prefix=/usr
make
make install

安装成功~ 大概就是这个样子~

先这样啦~

先说一声:新年快乐! 嘿嘿,但是并没有红包。

今天早上看到群里有学弟(其实是大神)说把网站添加了 https 的支持,突然想起来自己也该把我折腾证书这回事儿分享一下了,嗯嗯,开工!

话说自己网址支持 https 是在去年,那时候用过 startssl,还有国内的沃通,嗯~ 其实都还好吧,然后那时候也知道 letsencrypt,但是由于机器配置太太太低(编译都通不过好么),所以也就没用。再后来换了机器,嗯嗯,终于可以玩玩儿这货啦~(翻身农奴把歌唱,亚拉索~),不扯了,进入正题

先来安装

git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
./letsencrypt-auto --help

不多扯了,文档在这里

嗯嗯,生成证书

./letsencrypt certonly

然后就会出现一个 UI 界面,按照提示填写就好了

再然后配置一下 nginx

ssl_certificate /etc/letsencrypt/live/DOMAIN/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/DOMAIN/privkey.pem;

嗯嗯,记得替换成自己的路径哦~

OK,重启一下 nginx,看一下是不是已经成功了呢~

然后,letsencrypt 还有一点,证书是 90 天过期,那么就需要我们定时更新证书喽~ 哈哈,没问题

---- 2016.4.11 更新 ----

letsencrypt 更新到 0.4.0 以后就可以直接使用 renew 命令来更新证书了,这样会直接使用上次生成证书时的配置,简直方便,记得升级坂本哦~

使用 git pull 更新即可~

然后写一个 shell,这里替换证书需要先关闭 nginx,否则替换不成功

#!/bin/bash

cd /path/to/letsencrypt
/etc/init.d/nginx stop
./letsencrypt-auto renew
/etc/init.d/nginx start
crontab -e

在 crontab 中添加

0 0 31 * * /path/to/renew.sh > /path/to/renew.log

嗯嗯,打完收工~ 吃饭去,拜拜~

好吧,其实是因为自己老忘,然后这次迁移又忘记了,所以就顺手记一下吧

vim /etc/my.cnf

[mysqld]下添加

skip-networking

一般都是被注释掉的,去掉注释就好了

然后重启 mysql 就好了

嗯嗯,大概就是这样吧~
有点儿困,晚安~

好久之前遇到的,一直没有时间记录下,今天记录一下

贴个代码

import Component1 from "./component1.jsx";
import Component2 from "./component2.jsx";

这时候我们想要在 render 的时候动态判断,然后加载不同的组件,怎么办呢?
试试这个:

render() {
    let Comp = choose1 ? eval(Component1) : eval(Component2);
    
    return (
        <Comp prop1={data1} prop2={data2} />
    );
}

嗯嗯,大概就是这样~ 很简单吧~

好啦,就这样吧,晚安~

----------- 2016.08.31 更新 ----------------

好久没有写 react 了,最近又开始写的时候,发现已经不需要这么麻烦了

大概这个样子就可以

render() {
    let Comp = choose1 ? Component1 : Component2;
    
    return (
        <Comp prop1={data1} prop2={data2} />
    );
}

嗯嗯,就是这样!

昨天遇到的问题,公司的一个lnmp环境的机器忘记了 MySQL 的root密码,然后就呵呵呵呵呵。。。

下面其实就是记一下重置的过程

1.停掉LNMP

lnmp stop

2.修改MySQL配置文件

vim /etc/my.cnf

[mysqld]后面加入一行,停到密码验证

skip-grant-tables

3.重新启动LNMP

lnmp start

4.修改密码

mysql
update user set Password = password ( '123456' ) where user = 'root';

5.重启LNMP

lnmp restart

大功告成~

周末了解了一下HTTP2.0相关的一点儿东西,然后就迫不及待的在博客上搞一下试试。

博客是用的 Nginx 1.6 比较老的版本,然后 Nginx 在 1.9.5 的版本已经加入了 HTTP2.0 的扩展模块,之前的版本可以使用 SPDY 扩展模块来实现 SPDY 协议。

先不扯了,搞起搞起~

先升级一下 Nginx,下载最新的 Nginx 版本,现在最新是1.9.7,然后要下载最新的SSL模块,接下来就是编译安装啦

进到你的 Nginx 源码目录,配置要添加的模块,需要至少 http_v2_module 和 http_ssl_module 两个模块

./configure --with-openssl=../openssl-x.x.x --with-http_v2_module --with-http_ssl_module

然后

make

替换 nginx

mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old
cp objs/nginx /usr/local/nginx/sbin/nginx
make upgrade

OK,去HTTP/2 Test测试一下效果

哇哈哈哈,去看看速度测试跑个分儿

然后,据说 HTTP 2.0 在IE 11(据说只有win 10的IE 11才支持)以下都不支持,然后我在IE 10下打开了一下博客,貌似也能打开,但是是HTTP 1.1,难道会降级? 这个再研究一下~

好啦,就到这儿啦~