交互UI设计的一个原则猜想

对于大部分的右手习惯用户来讲,有一个事实:眼睛在左,右手在右。反映到交互UI上即:视觉在左,操作在右。

从符合人体工程学的角度想,这是否代表了一种设计原则呢?而且是非常朴素易懂的原则。

继续阅读~ 参与评论~

pm2部署遇到process.cwd报错的解决方法

最近在pm2.log中看见如下错误导致无法启动服务:

path.js:1144
          cwd = process.cwd();
                        ^

Error: ENOENT: no such file or directory, uv_cwd
    at Error (native)
    at Object.resolve (path.js:1144:25)
    at Function.Module._resolveLookupPaths (module.js:361:17)
    at Function.Module._resolveFilename (module.js:431:31)
    at Function.Module._load (module.js:388:25)
    at Module.require (module.js:468:17)
    at require (internal/module.js:20:19)
    at Object. (/usr/lib/node_modules/pm2/lib/ProcessContainer.js:12:15)
    at Module._compile (module.js:541:32)
    at Object.Module._extensions..js (module.js:550:10)

于是google之,在https://github.com/Unitech/pm2/issues/2057找到方法解决,记录如下:

首先导致这个错误是因为pm2最早启动的目录被删除了(删除后重建同名目录也是无用的)。

什么叫最早启动的目录呢?就是在命令行下第一次执行pm2时所在的目录,比如新装系统,在 /home/deploy 下第一次执行 pm2命令,那么 /home/deploy 就是最早启动的目录。再比如杀掉pm2进程后,再次在某个目录下执行了pm2命令,那这个目录也是最早启动的目录。

理解了最早启动的目录,那么当pm2启动后,把该目录删除过一次,则再次用pm2去启动node服务时就会报以上错误。

pm2 issues-2057中也有人指出了验证方法,如下:

  1. 先找到pm2的进程pid:
    ps ax | grep PM2
    
  2. 然后查询该进程执行时所在的目录(用上一步得到的pid替换下面命令的PM2_PID)
    ls -l /proc/PM2_PID/cwd
    
  3. 最后根据结果,如下的(deleted)标注,就说明该目录被删除过。
    $ ls -l /proc/24016/cwd
    lrwxrwxrwx 1 root root 0 Feb 4 17:04 /proc/24016/cwd -> /home/nodejs/deploy(deleted)
    

验证原因后,解决方法就是重新在另外一个安全一些的目录重启pm2进程。

先用pm2 kill命令杀掉pm2进程,然后 cd ~ 到home目录,执行 pm2 -v 命令,这样就在一个相对安全的目录启动了pm2。最后再去部署node服务就可以了。

继续阅读~ 参与评论~

莫名其妙的swigjs错误

场景是这样的,有一个自定义的tag,用到了_ctx.__require,代码片段如下:

var s = (ignore ? '  try {\n' : '') +
    'var _compiler = _ctx.__require("' + normalize + '");' +
    '_output += _compiler(' +
    ((onlyCtx && w) ? w : (!w ? '_ctx' : '_utils.extend({}, _ctx, ' + w + ')')) +
    ');\n' +
    (ignore ? '} catch (e) {}\n' : '');

然后之前使用过设置模板内变量的方法:

swig.setDefaults({
  locals: {
    'xxx': '11'
  }
});

一直相安无事,最近改了逻辑,去掉了setDefaults locals,结果一刷新页面(该页面使用了上述自定义tag),页面就报错:

TypeError: _ctx.__require is not a function

并且只是重启node服务后首次刷新页面才会出现,再次刷新就不会出现这个错误。。。搞得莫名其妙的,再次把locals set一下,就不会出现这种报错。 更奇特的是,locals不能是一个空对象{}, 必须至少有一对key:value。

暂时还不明确具体原因。

继续阅读~ 参与评论~

express请求流中的错误捕捉处理

nodejs中的错误处理还是比较麻烦的,尤其遇到异步回调之类,多层嵌套,简单的try…catch无法处理。

目前在用expressjs,拿此举例说说怎样实践。
第一种,从一介布衣那儿看到的方法,可行:

const domain = require('domain');
app.use((req, res, next) => {
  const reqDomain = domain.create();
  // next抛出的异常在这里被捕获,触发此事件
  reqDomain.on('error', e => {
    // ... 这里统一处理错误,比如渲染或跳转到404,500页面
  });

  return reqDomain.run(next);
});

通过在route定义之前添加如上的中间件,可以捕捉到大部分的错误。

第二种,上面说到是大部分的错误,因为我碰到了一个没成功捕捉到的,就是使用swig模板渲染时的变量报错。

// 设置模板引擎
app.engine('swig', swig.renderFile);
app.set('view engine', 'swig');
app.set('views', `${__dirname}/views`);
app.set('viewExt', '.swig');
// 在某处渲染输出: 
res.render('template/filepath');
// 如果在filepath.swig文件中有变量报错,则第一种方法不能成功捕捉

这时在stackoverflow找到一个方法,

// 依然按第一种方法写错误捕捉
// 然后在route之后再写个中间件

// 最后的错误处理,比如发生在res.render中的错误
// 由于已经设置了响应,因此只能发送状态码,或跳转
// next不能去除,否则无法获取到错误
app.use((err, req, res, next) => {
  // res.sendStatus(500);
  log.error(err);
  // res.redirect(301, '/'); // 跳转到首页
  next();
});

ok,经过验证,上述方法已经能够处理目前所有遇到的问题。

第三种,为什么会有这一种方法呢,纯属个人思维发散,由于是express内部处理了模板引擎,导致res.render方法不能正常抛出错误被外围捕捉,那么我直接用swig方法渲染文件,并把渲染后的结果通过res.send方法响应是不是可以呢?

// 之前是这样渲染的
res.render('template/filepath');
// 改为
res.send(swig.renderFile('/...这里应该是物理绝对路径.../template/filepath.swig'));

经过上面改造,发现只用第一种方法也可以正常捕捉到错误,说明推论正确。

之所以在第二种还能解决的情况下还在寻找其他方案,是因为第二种的最终错误处理只能响应状态码,而不能再渲染页面了。终究不够完美,方法不够优雅。

像第三种方式,完全可以不必设置express的模板引擎了,用res.send + 模板自身的渲染方法即可,封装为一个方法,方便调用。

继续阅读~ 参与评论~

arttemplate的jQuery帮助方法

需支持es5,兼容可以使用es5-shim

/**
 * 封装模板使用方法
 * @param  {string} tplName 模板名
 * @param  {[type]} data 传入模板的数据
 * @param  {[type]} method dom操作方法,默认使用html()方法
 * @return {[type]} 容器jQuery对象
 */
$.fn.tpl = function (tplName, data, method) {
  data = data || {};
  method = method || 'html';
  return this[method](template(tplName, data));
};
['append', 'prepend', 'after', 'before'].map(function (method) {
  (function (method) {
    $.fn[method + 'Tpl'] = function (tplName, data) {
      return this.tpl(tplName, data, method);
    }
  })(method);
});

继续阅读~ 参与评论~

网站内容劫持防范

互联网环境安全性还是比较差的,尤其是官方运营商都不要脸的进行了内容劫持往页面插入广告之类的,更是无语。主要防范方法是CSP + HTTPS。HTTPS都了解,CSP,中文名为 内容安全策略,可以参见https://developer.mozilla.org/zh-CN/docs/Web/Security/CSP

继续阅读~ 参与评论~

React传递属性给子级

写了一个mixin方法:

var React = require('react');

module.exports = {
    // 将属性传递给子级
    // Element: 子级类型, propsMap: 属性对象
    propsToChildren: function (Element, propsMap) {
        return React.Children.map(this.props.children,function(child) {
            if (child.type === Element) {
                return React.cloneElement(child, propsMap)
            } else {
                return child;
            }
        }, this);
    }
}

继续阅读~ 参与评论~

git使用rebase模式

一、概念上的用法:

1、同分支拉取使用:

git pull --rebase

2、不同分支衍合:

## local machine
(develop)$: git pull origin develop --rebase

## 切换到 feature 分支,衍合develop分支,如有冲突,解决冲突后continue,再次 commit
(develop)$: git checkout feature/user-extension
(feature/user-extension)$: git rebase develop
(feature/user-extension)$: ## ... 解决冲突
(feature/user-extension)$: git rebase --continue

(feature/user-extension)$: git commit origin feature/user-extension

二、本人实际用法:

同分支进行rebase,不同分支间进行merge。

其中同分支有两种情况:

1、本地分支无任何最新提交,远程有新提交。
执行 git pull 直接拉取即可。

2、本地分支有新提交,远程也有新提交。
执行 git pull –rebase 衍合远程分支。

参考:

http://blog.csdn.net/jackystudio/article/details/12309627

http://git-scm.com/book/zh/v1/Git-分支-分支的衍合

http://blog.isming.me/2014/09/26/git-rebase-merge/

http://blog.yorkxin.org/posts/2011/07/29/git-rebase/

http://hy2014.github.io/2014/07/25/git-rebase/

http://segmentfault.com/q/1010000000181403

继续阅读~ 参与评论~

1 2 3 4 5 6 26 27

全部分类
Books(4)code(7)database(6)html&css(24)java(11)JavaScript(48)jQuery(24)linux(20)python(1)React(1)share(1)soft(4)solution(53)thinking(17)vim(9)WordPress(8)前端优化(12)拓展(33)服务器(31)移动开发(4)自然(22)