由迭代器到js异步操作

什么是迭代器?

一个简单的列子

function makeIterator (arr) {
    let nextIndex = 0;
    //返回一个迭代器方法
    return {
        next: () => {
            if(nextIndex < arr.length){
                return {value: arr[nextIndex++], done: false}
            }else{
                return {done: true}
            }
        }
    }
}

const it = makeIterator([1,2,3]);

console.log('1:', it.next());
console.log('2:', it.next());
console.log('3:', it.next());
console.log('end:', it.next());
复制代码

执行结果:

1: {value: 1, done: false}
2: {value: 2, done: false}
3: {value: 3, done: false}
end: {done: true}
复制代码

上述为一个简单的迭代器,因为迭代器的代码过于繁琐,产生了生成器即Generator

什么是生成器?

较为简单的理解,生成器会返回一个迭代器,简化了代码,下面为一个生成器的列子。

function *makeIterator (arr) {
    for(let i = 0; i < arr.length; i++){
        yield arr[i];
    }
}
const gen = makeIterator(['a','b','c']);
console.log('1', gen.next());
console.log('2', gen.next());
console.log('3', gen.next());
console.log('end', gen.next());
复制代码

执行结果和上述相同:

1: {value: 1, done: false}
2: {value: 2, done: false}
3: {value: 3, done: false}
end: {done: true}
复制代码

有了上述关于迭代器和生成器的概念,我们来看下关于js的异步操作。

文件目录结构如下
async
│     
└───content.js
└───asyncRead.js
复制代码

content.js:

const content = '此js为测试js';
复制代码
  1. 普通的js回调
const fs = require('fs');
function readFile(cb){
    fs.readFile('./content.js', (err, data) => {
        if(err) return cb(err);
        cb && cb(null,data);
    })
}
//1. 回调函数
readFile((err, data) => {
    if(!err){
        //返回的是buffer类型
        console.log('data:', data);
        //返回正常内容
        console.log('data.toString():', data.toString);
    }else{
        console.log('err:', err);
    }
})
复制代码
  1. promise
const fs = require(fs);
function readFileAsync(path) {
    //定义了一个执行器
    return new Promise((resolve, reject) => {
        fs.readFile(path, (err, data) => {
            if(err) reject(err);
            else resolve(data);
        })
    })
}

readFileAsync('./content.js')
    .then(data => {
        console.log('data:', data.toString());
    })
    .catch(err => {
        console.log('err:', err);
    })
复制代码
  1. co + Generator + Promise 生成器的方法
const fs = require(fs);
const co = require('co');
const util = require('util');
const readFileFunc = util.promisify(fs.readFile);

co(function *(){
    let data = yield readFileFunc('./content.js');
    data = data.toString();
    console.log('data:', data);
})
复制代码
  1. async await (为Generator的语法糖,更加语义化)
const fs = require('fs');
const util = require('util');
const readAsync = util.promisify(fs.readFile);
async function init() {
    let data = await readAsync('./content.js');
    console.log('dataToString:', data.toString())
}
init()
复制代码

关于生成器原理的一点补充:

先看一个简单的例子:

function *gen(x){
    var y = yield x + 2;
    return y
}

var g = gen(1);
console.log(g.next());
console.log(g.next());
复制代码

输出结果:

Object {value: 3, done: false}
Object {value: undefined, done: true}
复制代码

分析上述执行结果:

调用generator函数,会产生一个内部指针(遍历器)g,这是 Generator 函数不同于普通函数的另一个地方,即执行它不会返回结果,返回的是指针对象。调用指针 g 的 next 方法,会移动内部指针(即执行异步任务的第一段),指向第一个遇到的 yield 语句,上例是执行到 x + 2 为止。

换言之,next 方法的作用是分阶段执行 Generator 函数。每次调用 next 方法,会返回一个对象,表示当前阶段的信息( value 属性和 done 属性)。value 属性是 yield 语句后面表达式的值,表示当前阶段的值;done 属性是一个布尔值,表示 Generator 函数是否执行完毕,即是否还有下一个阶段。

稍微复杂一点的实例:

var fetch = require('node-fetch');
//生成器
function* gen(){
  var url = 'https://api.github.com/users/github';
  var result = yield fetch(url);
  console.log(result.bio);
}
//gen()函数生成一个内部指针
var g = gen();
//执行next()方法,执行到yield交出执行权
var result = g.next();
//拿到返回结果,以为fetch返回的是promise对象,后面进行promise处理
result.value.then(function(data){
  return data.json();
}).then(function(data){
  g.next(data);
});
复制代码

参考链接:

Generator
Promise

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值