JS 异步编程之二:理解生成器(Generator)

作者:nunumick 发布时间:25 Jul 2017 分类: front-end

上篇学习了迭代器的应用原理,我们知道可以用生成器(generator)来返回迭代方法,简化对象迭代器的实现。这篇我们学习生成器的相关知识点。

先来看下官方定义:

The Generator object is returned by a generator function and it conforms to both the iterable protocol and the iterator protocol. Generator is a subclass of the hidden Iterator class.

可知 Generator 对象是迭代器的子类,同样遵循迭代协议。其作用就是用于生成迭代方法。

虽然自定义迭代器是一个有用的工具,但由于需要显式地维护其内部状态,因此创建时要格外谨慎。生成器函数(Generator 函数)提供了一个强大的替代选择:它允许你定义一个非连续执行的函数作为迭代算法。生成器函数使用 function* 语法编写。

//生成器函数内部每个yield语句定义了生成器暂停执行并返回值给调用者的一个点。
//当生成器恢复执行时,它会从暂停处继续,保持其内部状态不变。
function* geA() {
  yield "a1";
  yield "a2";
  yield "a3";
  yield "a4";
}

//显式调用geA()返回的迭代器对象
//自动反复调用其.next()方法,直到迭代器耗尽(即.next().done为true)
for (let item of geA()) {
  console.log(item);
}

/**
* output:
a1
a2
a3
a4
*/

异步编程

JS 的异步函数并不会阻塞代码执行顺序,想要通过按照异步函数编写的顺序来实现同步的执行结果并不容易。

(Read more ...)

标签: javascript , ecma , es6 , generator
<<< EOF

JS 异步编程之一:理解迭代器(Iterator)

作者:nunumick 发布时间:18 Jul 2017 分类: front-end

ES2017(ES8)发布了 async functions 和 await 关键字等特性,极大提升了编写异步程序的便利性和代码简洁度,应该说 async & await 是一种新的语法糖,为了说明这一点,我们可以将时间回调到 ES2015(ES6)的特性发布,逐一理解 iteratorgenerator 以及 TJ 大神写的中间产物 co库 的应用原理,进而了解 async functions 的本质。

可迭代对象

ES6 中引入了迭代器和可迭代对象(iterable)的概念,并且提供了对可迭代对象的相关支持,如 for…of 循环,本质上一个可迭代对象就是内置了迭代器方法的对象,因此可以说任何对象都能够被迭代,不仅仅是数组。

//创建一个名为arr的数组,并给它添加一个额外属性name。
const arr = [1, 2, 3, 4, 5];
arr.name = "test arr";

//使用传统的for循环遍历数组,通过索引访问并打印数组元素。
for (let i = 0; i < arr.length; i++) {
  console.log(arr[i]);
}

//使用for...of循环遍历数组。for...of适用于可迭代对象,自动调用其内置迭代器来获取每个元素。
for (let item of arr) {
  console.log(item);
}

//@@iterator
//数组都有内置迭代器方法,该方法由Symbol.iterator属性提供,返回一个迭代器对象。
console.log(arr[Symbol.iterator]);

//显式调用数组的Symbol.iterator方法并立即使用返回的迭代器对象进行遍历。
//这与直接使用for...of循环效果相同。
for (let item of arr[Symbol.iterator]()) {
  console.log(item);
}

迭代协议

迭代器是遵循了迭代协议的对象,协议规定迭代器必须实现 next() 接口,它应该返回当前元素并将迭代器指向下一个元素,返回的对象格式为 {value:元素值, done:是否遍历结束},其中,done 是一个布尔值。done 属性为 true 的时候,我们默认不会去读取 value, 所以最后返回的经常是 {value: undifined, done: true}

我们可以利用迭代协议规则,手动执行迭代,或者重写对象的迭代逻辑。

(Read more ...)

标签: javascript , ecma , es6 , iterator
<<< EOF

前端系统初始化-我的常用工具

作者:nunumick 发布时间:23 Jan 2015 分类: developer

每次换电脑总是要走一遍繁琐的软件安装和开发环境初始化流程,在mac上安装软件、命令行工具时不时会碰到问题,在又一次经历了这个过程之后,我决定把常用软件及开发环境记录下来,以绝后患。

brew

mac 上强力资源管理工具,用的是HomeBrew

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

nodejs

无需多说,官网下载安装:nodejs.org

接着可以装一些 node 常用工具

java-jdk

无需多说,官网下载安装:jdk download

git

安装git

brew install git

常规配置

git config --global alias.st 'status'
git config --global alias.ci 'commit'
git config --global alias.br 'branch'
git config --global alias.co 'checkout'
git config --global alias.lg 'log'
git config --global user.name 'name'
git config --global user.email 'email'

ssh配置

从个人仓库同步 .ssh 到本机相同目录下即可

svn

brew install --universal --java subversion

zsh

比较好用的shell,可以简化不少操作,自动补全,颜色高亮,还能识别git仓库

(Read more ...)

标签: jekyll , vim , git , zsh
<<< EOF

CodeIgniter 学习笔记

作者:nunumick 发布时间:22 Apr 2014 分类: back-end

CodeIgniter

CodeIgniter 简称:CI,是一个应用程序框架

MVC

CI 使用 MVC 模式来构建应用,可以构建复杂的应用程序,MVC 对应的文件分别存放在 models、views、controllers 目录下,支持子目录结构。

模型

CI 通过模型类来定义和数据库的交互动作,如增删改查等基本的数据库操作。

视图

视图用于把内容展现给用户,在视图中可以使用在 controller 或 model 中定义的全局对象。

控制器

控制器负责与用户响应交互,选择一个对应的方法来对应用户请求,让模型和视图有序结合,控制器是整个应用的核心。

路由

路由负责中转用户的请求到控制器,CI 默认采用 URI 分断的方式来到达控制器,可以在 config/routers.php 中配置自定义的路由,如果开发者觉得分段方式不爽,也可以重写路由类,然后用自己路由。

配置

CI 的强大之处在于系统中的很多设定都是可以由用户自己配置的,包括数据库、语言、路由、自动装载、钩子、类名前缀、应用目录、系统目录等配置。

一般的,以上配置都放在 application/config 目录下,全局的配置文件是application/config/config.php,在系统初始化时将会被自动加载。

类定义&重写&类扩展

CI 的工程目录每一个都是有作用的,CI 基于目录索引和串联应用逻辑,我们可以在目录中定义自己的类和辅助函数,也可以重写系统默认提供的类和辅助函数。

应用程序目录 — application,支持子应用,如 application/foo/ 系统目录 — system

与系统目录对应,应用程序目录中同样有 core、helpers、libraries 目录,在这些目录下我们可以定义自定义的类和辅助函数,也可以直接覆盖系统的类和辅助函数。

钩子

简单理解,CI 的钩子提供了面向切面的编程方法,可以让开发者无侵入的在系统中插入自己的逻辑。

资源装载

CI 提供了很多方法类和辅助函数,考虑到系统性能,CI 只在初始化时装载一些必要的类和函数,比如 Router 和 Input。用户想要装载资源可以通过 Loader 达成,也可以在 autoload 中配置全局的资源加载。

错误处理

CI 默认提供了四种错误模板,存放在 errors 目录下,开发者可以在该目录下定义自己的错误展示模板。有三种错误级别:错误、调试、信息。

缓存

为了让用户访问响应更快,CI 支持把内容输出到本地磁盘保存起来,使用 output 即可,缓存可以设置过期时间。

输入输出类

CI 默认封装了不少输入输出类,这些类或方法帮助开发者更方便快捷、更安全的开发应用而不用考虑其他繁琐的步骤,比如获取 POST 数据,使用 $this->input->post(‘abc’)即可,不用在乎 ’abc’ 是否已经设置。类似的还有 cookie、session、表单校验 等等很多很多。

标签: codeIgniter , php , ci
<<< EOF

使用 grunt 管理 jekyll 博客

作者:nunumick 发布时间:16 Jan 2014 分类: blog

自从使用了 jekyll ,我就一直用它来构建自己的博客,然后把页面托管在 github.com 上,很是方便。

不过 github 为了安全考虑,没有支持 jekyll 的插件 _plugin,但有些插件我们是很需要的,比如分类、标签插件,你很难想象没有这类索引插件的博客是什么样子,我觉得 github 应该开放这类插件,遗憾的是至少目前没有开放。

我的做法是先在本地使用插件构建好静态文件提交到 github,我猜很多人也是这样的。比如分类插件,jekyll 会调用插件在 site 目录下构建出一个 categories 目录,里面是所有分类的索引文件,然后我再手动把 categories 目录拷贝到根目录,之后 git 提交经由 github 的内置 jekyll 生成到站点的 site 目录,所有工作都是手动完成,有够蛋疼。

使用grunt自动构建

众所周知,grunt 是很赞的自动化任务构建工具,可以很方便的管理自己的项目。我尝试用 grunt 让搭建 jekyll 博客更智能化,主要用到

  • grunt-contrib-copy
  • grunt-contrib-clean
  • grunt-contrib-watch
  • grunt-shell-spawn

这几个任务模块。

设置Gruntfile:

module.exports = function(grunt){
  grunt.initConfig({
      pkg: grunt.file.readJSON('package.json'),
      clean: ['categories'],
      copy:{
        categories: {
          expand: true,
          cwd: '_site/',
          src:'categories/**',
          dest:'./'
        }
      },
      shell: {
        jekyll:{
          command: 'jekyll build',
          options: {
            async: false
          }
        },
        gitadd:{
          command: 'git add -A',
          options:{
            async:false
          }
        },
        gitci:{
          command: 'git ci -m "update pages"',
          options:{
            async:false
          }
        },
        gitpush:{
          command: 'git push origin master',
          options:{
            async:false
          }
        }
      },
      watch: {
        jekyll: {
          files: ['_posts/*.md','_posts/**/*.md','_layout/*.html', '_includes/*.html'],
          tasks: ['default']
        }
      }
  });

  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-shell-spawn');
  grunt.loadNpmTasks('grunt-contrib-watch');

  grunt.registerTask('default', ['clean','shell:jekyll','copy:categories']);
  grunt.registerTask('git', ['default','shell:gitadd','shell:gitci','shell:gitpush']);
}

每次更新博客只需在命令行敲入:

  grunt watch

之后只管自己写文章、更新、保存,每有动作,grunt 就会自动调用 jekyll 构建文章和分类,并且还能自动完成原本需要我手动操作的繁琐工作,是不是更方便了。

grunt-shell-spawn

值得一提的是shell-spawn这个模块,可以执行命令,使用同步的方式可以完成一些列的命令行任务,超赞!

options:{
  async:false //使用同步方式
}

自动提交git

顺便做了自动构建并提交到 github 的任务。

执行结果:

nunumicktekiMacBook-Pro:blog nunumick$ grunt git
Running "clean:0" (clean) task
Cleaning categories...OK

Running "shell:jekyll" (shell) task
Configuration file: /Users/nunumick/blog/_config.yml
            Source: /Users/nunumick/blog
       Destination: /Users/nunumick/blog/_site
      Generating... done.

Running "copy:categories" (copy) task
Created 10 directories, copied 18 files

Running "shell:gitadd" (shell) task

Running "shell:gitci" (shell) task
[master 0a6351b] update pages
 1 file changed, 39 insertions(+), 6 deletions(-)

Running "shell:gitpush" (shell) task
>> To git@github.com:nunumick/nunumick.github.com.git
>> 6e0b655..0a6351b  master -> master

Done, without errors.

标签: grunt , jekyll , blog , github
<<< EOF