如何给前端工具设置代理

在天朝,当一个开发者非常苦逼,因为说到开源,就是相互交流,而有堵墙总是在阻断这个交流的过程,不断想要把我们困在笼子里。比如你查个技术文章,这时候“CONNECTION RESET”了,装个 npm 包,一直打转,死活装不上,这时候程序员的内心都是抓狂的。因此科学上网是大家必须掌握的技能,这篇文章不是探讨这个,假设你已经有了梯子,现在介绍下各个工具比如 Sublime Text、npm 等如何设置代理。

ss

假设本地开启的 http 代理为 http://127.0.0.1:1080。(Shadowsocks 默认就是这个地址)。ss 是一个很棒的工具,虽然作者被喝茶现在不维护了,但仍然可以由别人进行下去,在此向 clowwindy 的付出表示敬意。如果用的是 Mac 版 ShadowsocksX,默认只开启了一个 SOCKS5 代理,没有 http 代理,可以利用 polipo 来转换成 http 代理,简单介绍一下方法:

先安装 Homebrew,然后执行下面命令安装 polipo:

brew install polipo

然后,修改 /usr/local/opt/polipo/homebrew.mxcl.polipo.plist 文件,找到 <string>/usr/local/opt/polipo/bin/polipo</string> 这句,在下面添加一行:

<string>socksParentProxy=localhost:1080</string>

其实是把 http 流量导到 localhost:1080 的 SOCKS 代理上。第三步,设置开机启动:

ln -sfv /usr/local/opt/polipo/*.plist ~/Library/LaunchAgents

设置完成后,还需要手动启动一下 polipo:

launchctl load ~/Library/LaunchAgents/homebrew.mxcl.polipo.plist

这时就 OK 了,polipo 生成的 http 代理,默认地址为 localhost:8123。如果想要暂时终止 polipo,可以执行:

launchctl unload ~/Library/LaunchAgents/homebrew.mxcl.polipo.plist

Sublime Text

这里其实是给 Package Control 设置代理,方法:

打开“Preferences -> Package Settings -> Package Control”-> Settings – User,写入下面键值:

{
  "http_proxy": "127.0.0.1:1080"
}

npm

npm 其实有两个办法,一是用 cnpm,这是淘宝提供的一个 npm 镜像,好像是每 15 分钟跟 npm 同步一次。安装好了以后,你需要用 cnpm 命令来代替 npm 命令使用。安装方法(先装好 npm):

npm install -g cnpm --registry=https://registry.npm.taobao.org

用了这个就不用担心很慢的问题了。

第二个办法是给 npm 设置代理,运行以下命令行:

npm config set proxy http://127.0.0.1:1080 --global
npm config set https-proxy http://127.0.0.1:1080 --global

注意 --global 标志,表示配置被写入系统配置文件。Windows 下位于 C:\Users\用户名\AppData\Roaming\npm\etc\npmrc,Mac 下位于 ~/.npmrc)

Atom

C:\Users\用户名\.atom 下建立 .apmrc 文件(Mac 对应 ~/.atom/.apmrc),写入:

proxy = http://127.0.0.1:1080
https-proxy = http://127.0.0.1:1080

当然也可以用类似上面的 npm 命令,只要把 npm 换成 apm 就行了。

阅读全文 »

ES6 快速上手:模块

es6-small

ES6 引入了原生的模块支持。

一个 ES6 模块就是一个 JS 文件,除了以下两个区别:

  • 会自动开启严格模式
  • 可以使用 importexport 关键字

ES6 模块还有一些特点:

  • 模块中声明的变量都是私有的,即使在最外层作用域声明
  • 在模块最外层,this 指向 undefined

模块中声明的变量,默认都是私有的。如果要暴露给其他模块使用,需要 export

// mod1.js
export function foo(a, b, c) {
  ...
}
export class Bar() {
  ...
}

export 可以用在 function, class, var, let, const 前。如果输出的是上例中的 functionclass 声明,则必须有函数名或类名,不能匿名。

如果想要一次性导出多个接口,也可以这样写:

export {foo, bar};

export 语句必须放在最外层,也就是,不能在语句块中 export

import 用来导入模块:

import {foo} from "mod1.js";

或者,导入多个接口:

import {foo, bar} from "mod1.js";

mod1.js会被提前导入并加载。注意导入以后生成的变量 foobar 都是常量,类似 const。所以你不能再声明一个同名变量,或者修改 foobar

你也可以将模块的所有接口整个导入:

import * as myModule from "mod1.js";

这样 mod1.js 的所有接口都被绑定在了 myModule 对象上。你可以在 myModule 上调用 myModule.foo()

不管被导入多少次,一个模块内的代码始终只执行一次:

import { foo } from "mod1.js";
import { bar } from "mod1.js";

重命名接口

导入时,可以给接口重命名:

import {foo as bar} from "mod1.js";

导出时也可以:

export {
  foo as foo1,
  bar as bar2
};

重命名以后,只能使用新的名字。

default

每个 ES6 模块可以有一个默认导出,使用的是 default 关键字:

export default function(a, b) {
  ...
}

export default 关键字后可以跟随任何值。使用 default 时,函数可以是匿名的。

你也可以指定某一个变量为 default

let myObject = {
  foo() {
    return "foo...";
  },
  bar: 66
};
export {myObject as default};

要将一个模块的默认导出 import 进来:

import myModule from "mod1.js";

注意 myModule 没有了花括号。此时在 myModule 上就可以调用 foobar 了。

这种设计是为了与已存在的 CommonJS 和 AMD 模块相兼容。以 jQuery 为例:

import $ from "jquery";

一个模块只能有一个默认导出。但也可以同时存在非默认的导出:

// mod2.js
export let a = 123;
export default function(b, c) {
  ...
}

可以这样把两者一同导入进来:

import foo, { bar } from "mod2.js";

注意非默认的导出总是有一对花括号。默认导出也可以放进括号里,下面语句是同样的作用:

import { default as foo, bar } from "mod2.js";

阅读全文 »

ES6 快速上手:生成器

es6-small

生成器又叫“Generators”,是 ES6 的一个重要的新特性。

生成器是一种特殊的函数,下面就是一个生成器:

function* demo(name) {
  yield "Hi " + name + "!";
  yield "Welcome!";
  yield "Goodbye!";
}

调用以后,它返回一个迭代器。里面的 yield 关键字,用来指定每次调用 .next() 所应该返回的值。调用一下:

var iterator = demo("William");

iterator.next(); //{ value: "Hi William!", done: false }
iterator.next(); //{ value: "Welcome!", done: false }
iterator.next(); //{ value: "Goodbye!", done: false }
iterator.next(); //{ value: undefined, done: true }

可以看到,生成器函数的一个特点,就是每次遇到 yield 关键字,函数的执行都会暂停,yield 后面的表达式的值被返回。再调用 .next() ,函数就往下执行,到下一个 yield

生成器也有表达式语法:

let myGenerator = function *(arg) {
  ...
};

生成器的语法要点就两部分:function*yield* 两边允许空格的存在,只要是在 function 和函数名之间就可以。 yield 后面可以跟任意的表达式。

生成器的主要用处是两个:作为迭代器,异步编程。

作为迭代器使用

生成器作为一种函数,它可以成为对象的属性。回想一下《for…of 和迭代器》中所讲的可遍历对象,只要对象拥有一个能返回迭代器的 [Symbol.iterator]() 方法,就能成为一个可遍历对象。既然生成器正好就返回一个迭代器,所以,生成器就是 [Symbol.iterator]() 方法的最佳选择。比如:

var o = {
  items: [1, 2, 3],
  [Symbol.iterator]: function *() {
    for(let i = 0; i < this.items.length; i++) {
      yield this.items[i];
    }
  }
};

用 ES6 新的简写语法,还可以这样写:

var o = {
  items: [1, 2, 3],
  *[Symbol.iterator]() {
    for(let i = 0; i < this.items.length; i++) {
      yield this.items[i];
    }
  }
};

生成器里也可以使用 return 来提前结束遍历:

function *foo() {
    yield 1;
    return;
    yield 2;
    yield 3;
}
let iterator = foo();

iterator.next(); // { value: 1, done: false }
iterator.next(); // { value: undefined, done: true }

迭代器的 .next() 方法还可以传参,比如

function *createIterator() {
    let first = yield 1;
    let second = yield first + 2; // 4 + 2
    yield second + 3; // 5 + 3
}

let iterator = createIterator();

iterator.next(); // { value: 1, done: false }
iterator.next(4); // { value: 6, done: false }"
iterator.next(5); // { value: 8, done: false }"
iterator.next(); // { value: undefined, done: true }

传给 .next() 的参数,会变为上一个 yield 的返回值。因此,第一次调用 .next() 时不要传参数,传了也获取不到。

解析一下上例的执行过程:第一次调用 .next() 时,生成器内部的代码开始执行。第一句是一个赋值语句 let first = yield 1; 自右向左计算,所以先 yield 1,暂停了。第二次调用 .next() 并传入了 4,函数继续执行左边部分 let first = ...,因为 4 成为 yield 的返回值,所以 let first = 4。第二行同理,在 yield first + 2 也就是 yield 6 暂停。第三次调用 .next(5)以后,let second = 5,最后 yield second + 3 的结果是 8。

生成器另一大用处是在异步编程中,因为生成器有暂停的功能。执行一个异步函数时,可以 yield 暂停,等到异步任务完成,再调用 .next() 继续。

yield*

生成器还可以委托,说白了就是,在生成器中调用另一个生成器,例如:

阅读全文 »

ES6 快速上手:for…of 和迭代器

es6-small

for ... of 是 ES6 新增的循环语句,可以遍历一个集合(比如数组),用来代替普通的 for 循环或 forEach。一个例子:

var myArray = ["a", "b", "c"];
for (var value of myArray) {
  console.log(value);
}

那用 for ... of 有什么好处呢?显然用 forEach 也能遍历数组元素,但是 forEach 的缺陷是无法响应 break, continue, return 语句。所以,不能自由跳出,只能循环到底。另外有一个小提示,在大多数浏览器中 forEach 遍历都比 for 循环要慢。虽然 forEach 更简洁,但是从执行效率考虑应当使用 for

然后你会想到用 for...in,但 for...in 也存在一个问题,就是 for...in 给出的索引都是字符串,比如:

var myArray = ["a", "b", "c"];
for (var value in myArray) {
  console.log(value); //"0", "1", "2"
}

如果你直接拿这些索引来做运算,就会出错,比如 value + 10,会得到 "010" 而不是 10。而且,for...in 不光遍历数组内的元素,如果你往数组上添加了自定义的属性,也会被遍历出来。还有一点,最糟糕的情况下,for...in 还可能会不按 0、1、2……的顺序进行遍历。

for...of 可以克服以上这些缺点。它既支持 break, continue, return,同时,索引的类型和原来类型保持一致,对于数组,索引就是 Number 类型。

for...of 也可以遍历类数组对象,比如 NodeList 类型。

还能用来遍历字符串,会把它当作是字符序列:

for (var char of "(⊙ˍ⊙)") {
  alert(char);
}

还支持遍历 MapSet 对象。因为 Map 对象都是键值对,所以,需要使用解构赋值:

for (var [name, age] of persons) {
  console.log(name + "'s age is: " + age);
}

但是 for...of 并不支持遍历普通对象。你可以用 for...in 代替,或者借助 Object.keys

for ( var key of Object.keys(obj) ) {
  console.log(key + ": " + obj[key]);
}

除了上面提到的类型,在其他对象上调用 for...of 会抛出错误,包括nullundefined。为什么?因为 for...of 需要有迭代器的配合。

迭代器(iterators)

“迭代器”:简单来说,迭代器的核心就是一个 .next() 方法,每次调用 .next(),应该返回一个类似下面的对象:

{
  value: 100,
  done: false
}

假设 a[1, 2, 3] 的迭代器,那么每次调用迭代器的 .next(),应该是这样的结果:

a.next(); // { value: 1, done: false }
a.next(); // { value: 2, done: false }
a.next(); // { value: 3, done: false }
a.next(); // { value: undefined, done: true }

可以看出,每次返回的 value 就是从数组中抽出的一个元素,一直遍历到最后,done 表示状态,当它变为 true 时,遍历就结束了。

迭代器的作用就是用来遍历集合,再对里面的数据进行处理,就像我们经常用的 forEach 一样。迭代器的好搭档是 for...of

可遍历对象(iterables)

前面说了,只有在数组、NodeListSetMap、字符串上可以使用for...of,因为它们都是可遍历对象,称为“iterables”。在普通对象上使用 for...of 会抛出错误。

什么是可遍历对象?简单来说,只要对象上拥有一个 [Symbol.iterator]() 方法,该方法返回一个迭代器。那这个对象就是可遍历的,可以用 for...of 进行遍历。

[Symbol.iterator]() 所返回的迭代器又叫默认迭代器(default iterator)。上面所讲的那些类型,都内置了默认迭代器,所以能在 for...of 中使用。

阅读全文 »

flight