在for循环体内进行条件改变的一个坑

先说一个众所周知的作用域问题,看一下代码:

var a = [];
for (var i = 0; i < 5; i++) {
  a.push(function () {
    console.log(i)
  });
}
a[0]();
a[1]();

以上期望输出0, 1,实际输出则是 5,5。因为i的作用域是window(global)全局。

ES6有个解决办法,把var关键字改为let关键字,即可解决作用域问题。原理可以通过babel转换一下源码探知:

var a = [];
var _loop = function _loop(i) {
  a.push(function () {
    console.log(i);
  });
};
// 源码是let声明,此处经过了babel转换
for (var i = 0; i < 5; i++) {
  _loop(i);
}

通过循环体封装为_loop函数,把i转为一个函数内部变量,不再受循环外变量影响。

而此时也该点题了,本文题目说的是另外一个隐藏的坑。见以下代码:

const a = [];
for (let i = 0; i < 5; ) {
  a.push(function () {
    console.log(i)
  });

  i++; // 条件改变放到循环体内
}
a[0](); 
a[1]();

不同之处也已标明:i++的条件改变位置换到了循环体内执行,这时预期结果也不一样了。
执行预期应该是输出0, 1,实际却输出的是 1, 2。

这是为什么呢?同样通过babel转换源码后探知:

var a = [];

var _loop = function _loop(_i) {
  a.push(function () {
    console.log(_i);
  });
  _i++; // 循环体内的条件改变影响到循环体函数内的局部变量

  i = _i;
};

for (var i = 0; i < 5;) {
  _loop(i);
}

a[0]();
a[1]();

最近也是在写一个比较复杂的业务逻辑时,发现这种写法的问题,好在花费了一些时间总算是搞清楚了。

如果循环体是即时执行是不会有问题的,如果是延迟执行的则会暴露该问题。

继续阅读~ 参与评论~

慎用image crossOrigin属性

使用Image对象预加载图片:

const img = new Image();
img.crossOrigin = 'anonymous';

如果设置了crossOrigin,就要小心了。若在html <img/>标签内没有使用该属性,会造成两次图片请求,达不到预加载的效果。

原理是crossOrigin属性会在http请求头增加Origin头,导致两次请求是不同的(类似请求地址增加随机数去缓存效果)。

但是crossOrigin在处理canvas图片跨域报错时,是有用的。

继续阅读~ 参与评论~

vue的component标签特殊性

今天发现vue实现动态组件的内置标签<component>有点特殊性,当使用自闭方式使用它时(<component />)对同级的兄弟标签,在component前的可以渲染出来,在component后的则不能渲染。

例如:

<div>
<p>aaaa可以渲染出来</p>
<component />
<p>bbbb渲染不出来</p>
</div
在浏览器界面,是看不到bbbb这行的。使用<component></component>这种方式就可以避免这个问题。

继续阅读~ 参与评论~

路由设计范式

常见的路由范式,拿产品product举例:

产品列表页: /product
产品详情页: /product/:id
产品编辑新增: /product/edit/:id? 有id表示编辑,无id表示新增
产品删除: /product/delete/:id

比较简单有效,无多余单词,以上供参考。

相对的根据大功能模块扩展,比如文章模块和商城模块,分别在以上范式基础上,加商定的模块前缀:/article 和 /mall

路由一般情况下应可以逐级追溯:例如 /mall/product/:id/comment

第一级:/mall 商城模块主页
第二级:/mall/product 商城产品列表
第三级: /mall/product/:id 某产品详情
第四级: /mall/product/:id/comment 该产品下的评论列表

以上可以作为设计路由时遵循的思路。

继续阅读~ 参与评论~

如何在js循环中使用async/await

在开发maty.js时,遇到一个数组任务,数组项是内部异步执行的函数,期望是同步依次执行每项函数,每项函数执行完本身的异步任务后,继续下一项。

刚开始单纯使用map来循环执行,并且await每项函数。如下所示:

starters.map(async (fn, i)=> {
  console.log('++++++++++: ', i)
  await fn(ctx);
});

结果是依次先输出了索引i,而不是阻塞每次循环,按期望执行。

搬出Google大法,在https://blog.lavrton.com/javascript-loops-how-to-handle-async-await-6252dd3c795中得到解决办法,对在 for…of 循环语法中使用await是有效的。

for (const fn of starters) {
  await fn(ctx);
}

同时文章中指出使用Promise.all,是无法解决当前问题的,因为all方法是并行运行的。很奇怪为什么没有串行执行的原生方法。

继续阅读~ 参与评论~

自定义nodejs transform

nodejs transform可以用于对stream的数据修改定制,并返回修改后的stream。对于其用法,官方文档其实并不好理解,找到两篇文章可以帮助理解:

1、http://fred-zone.blogspot.com/2017/09/nodejs-transform-stream.html 说明的比较浅显易懂。

2、https://juejin.im/post/5a4a377151882546f00a68c9 涉及比较多的内容和例子。

有这两篇就够了。

继续阅读~ 参与评论~

centos 7下使用puppeteer访问页面报错解决

完整的报错信息如下:

{ Error: socket hang up
    at createHangUpError (_http_client.js:330:15)
    at Socket.socketOnEnd (_http_client.js:423:23)
    at Socket.emit (events.js:164:20)
    at endReadableNT (_stream_readable.js:1062:12)
    at process._tickCallback (internal/process/next_tick.js:152:19) code: 'ECONNRESET' }
(node:29975) UnhandledPromiseRejectionWarning: Error: socket hang up
    at createHangUpError (_http_client.js:330:15)
    at Socket.socketOnEnd (_http_client.js:423:23)
    at Socket.emit (events.js:164:20)
    at endReadableNT (_stream_readable.js:1062:12)
    at process._tickCallback (internal/process/next_tick.js:152:19)
(node:29975) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:29975) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

继续阅读~ 参与评论~

1 2 3 4 5 6 27 28

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