前言
纯属个人学习过程中的笔记,方便后续的复习,如果有错误或者更好的方法,希望看到的大佬不吝赐教
Generator
学习Generator之前,需要简单了解一下迭代器
迭代器
有next方法,执行返回结果对象,返回的对象有done和value两个属性
下面用代码看一下迭代器是个什么东西
function createIterator(list) {
let i = 0;
return {
next() {
let done = i >= list.length;
let value = !done ? list[i++] : undefined;
return {
done,
value,
};
},
};
}
let iterator = createIterator([1, 2, 3]);
console.log(iterator.next()); //{ done: false, value: 1 }
console.log(iterator.next()); //{ done: false, value: 2 }
console.log(iterator.next()); //{ done: false, value: 3 }
console.log(iterator.next()); //{ done: true, value: undefined }
Generator(生成器)
- ES6异步编程解决方案
- 通过function* 声明
- 返回符合可迭代协议和迭代协议的生成器对象
- 在执行时能暂停,又能从暂停处继续执行
yield
- 只能出现在Generator函数中
- 用来暂停和恢复生成器函数
next
- 遇到yeild暂停,将紧跟yeild表达式的值作为返回对象的value
- 没有yeild,执行到return ,将return的值作为返回对象的value
- 没有return 返回对象的value是undefined
- next可以携带一个参数,可以作为上一个yeild(暂停的那个)表达式的返回值
function* generator() {
let first = yield 1;
let second = yield first + 2;
let thrid = yield second + 3;
return 1;
}
let g = generator();
console.log(g.next()); // {value: 1, done: false}
console.log(g.next(2)); // {value: 4, done: false}
console.log(g.next(3)); // {value: 6, done: false}
console.log(g.next()); // {value: 1, done: true} //如果没有return ,value则是undefined
yeild*
- 是生成器函数/可迭代对象
- 可以委托其他生成器
- 用来复用生成器
通俗的说,就是yeild* 可以在生成器中调用另外一个生成器,还是看代码
function* generator1() {
yield 1;
}
function* generator2() {
yield 100;
yield* generator1();
yield 200;
}
let g2 = generator2();
console.log(g2.next()); //{value:100,done:false}
console.log(g2.next()); //{value:1,done:false}
console.log(g2.next()); //{value:200,done:false}
console.log(g2.next()); //{value:undefined,done:true}
return
- return,可以带一个参数,结束生成器的执行,返回对象的value为传的参数,不传则为undefined
function* generator() {
yield 100;
yield 200;
}
let g = generator();
console.log(g.next()); //{value:100,done:false}
console.log(g.return(123)); //{value:1,done:true}
console.log(g.next()); //{value:undefined,done:true }
throw
- 可以让生成器内部抛出错误
function* generator() {
let first = yield 1;
let second;
try {
second = yield first + 2;
} catch (error) {
second = 6;
}
yield second + 3;
}
let g = generator();
console.log(g.next()); //{value:1,done:false}
console.log(g.next(1)); //{value:3,done:false}
//可以看出由于有trycatch,抛出的错误被捕获到,所以走到了catch里面,second为6
console.log(g.throw(new Error("error"))); //{value: 9, done: false}
console.log(g.next()); //{value:undefined,done:true}
协程
Generator是怎么实现的呢,需要了解一下协程
协程:可以暂停执行(暂停的表达式称之为暂停点),也可以从挂点恢复执行(保留其原始参数和局部变量)
一个线程存在多个协程,但是只能同时执行一个协程
Generator就是协程在ES6上面的表现
yield就是挂起协程,next则是唤醒协程
Generator函数的应用
用setTimeout 模拟异步 //这种方法虽然不会造成回调地狱,但是代码耦合度比较高
function* generator() {
function test(num) {
setTimeout(() => {
console.log(num);
g.next(num);
}, 2000);
}
let r1 = yield test(1);
console.log(r1, "r1");
let r2 = yield test(2);
console.log(r2, "r2");
}
let g = generator();
g.next();
thunk
为了解决上述代码的耦合问题,需要使用thunk函数,可以自动执行Generator函数
函数比较绕,先上完整代码,然后慢慢理解
const fs = require("fs");
function thunk(fn) {
return function(...args) {
return function(callback) {
return fn.call(this, ...args, callback);
};
};
}
let readFileThunk = thunk(fs.readFile);
function* generator() {
let r1 = yield readFileThunk("./test1.json");
console.log(r1, "r1");
let r2 = yield readFileThunk("./test2.json");
console.log(r2, "r2");
let r3 = yield readFileThunk("./test3.json");
console.log(r3, "r3");
}
function run(fn) {
let gen = fn();
function go(data, err) {
console.log(data, err, "data123");
let result = gen.next(data);
if (result.done) return;
result.value(go);
}
go();
}
run(generator);
readFileThunk
function(...args) {
return function(callback) {
return fs.readFile.call(this, ...args, callback);
};
};
result.value
function(callback) {
return fs.readFile.call(this, ...args, callback);
};
run
的参数是生成器,运行之后拿到迭代器gen,然后执行next方法,如果返回的对象的value是false,则将go作为result.value的参数,result,value执行的时候,意味着fs.readFile执行,传入的callback(go)将作为fs.readFile的参数(回调函数)执行,然后又再一次回到了go函数内部,反之返回对象的value是true 的时候,则结束执行
async/await
async/await是Generator和promise的语法糖
async
- 返回值:返回一个promise对象,return的值是promise resolved时候的value,Throw的值是promise rejected时候的reason
async function test1() {
return 1;
}
let p1 = test1(); //一个promise
p1.then((res) => {
console.log(res); //1
});
async function test2() {
throw new Error("error");
}
let p2 = test2();
p2.catch((err) => {
console.log(err); //Error: error
});
await
- 只能出现在async函数内部或者最外层
- 等待一个promise对象
- await的promise对象状态为rejected的时候,后续执行中断
- 如果希望执行,可以在后面加一个catch或者在trycatch中执行
async function test() {
console.log(1);
await Promise.resolve().then(() => {
console.log(2);
});
console.log(3);
}
test(); // 1 2 3
async function test() {
console.log(1);
await Promise.reject();
console.log(3);
}
test(); // 1
async function test() {
console.log(1);
await Promise.reject().catch((err) => {
console.log(2);
});
console.log(3);
}
test(); // 1 2 3
async function test() {
console.log(1);
try {
await Promise.reject();
} catch (error) {
console.log(2);
}
console.log(3);
}
test(); // 1 2 3
async函数使用
async function test() {
console.log(1);
await new Promise((resolve, reject) => {
setTimeout(() => {
console.log(2);
resolve();
}, 3000);
});
console.log(3);
await new Promise((resolve, reject) => {
setTimeout(() => {
console.log(4);
resolve();
}, 2000);
});
}
test(); //1 2 3 4
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!