具体来说他们晓得generator表达式是两个计算机程序,它会回到两个插值器第一类,那个第一类有两个next方式,透过初始化next方式就能从外部赢得generator的继续执行控股权,
他们也能透过value领到继续执行后的结论,因此generator也能用以处置触发器。
比如:
function* fetchGenerator() {
const url = https://baidu.com;
const res = yield fetch(url);
return res;
}
他们在初始化gen表达式去赢得回到结论的这时候,就如需那么做:
const gen = fetchGenerator();
const result = gen.next();
result.value.then(data => data.json()).then(data => gen.next(data));
这里fetch回到的是两个promise,因此result.value就是两个pr然后再将data传递给gen.next(),这样就能将data赋值给yield左边的res,这样就能领到fetch的请求结论了。
然后这只
function* fetchGenerator(){
const res1 = yield fetch(https://baidu.com);
const res2 = yield fetch(https://google.com);
const res3 = yield fetch(https://bing.com);
return [res1, res2, res3];
}
const gen = fetchGenerator(),
result = gen.next();
result.value
.then(data => data.json())
.then(data => gen.next(data).value)
.then(data => data.json())
.then(data => gen.next(data).value)
.then(data => data.json())
.then(data => gen.next(data).value)
那么有没有一种方式,能不需要他们自己手动初始化next,而是让generator自动继续执行呢?他们能利用while循环来做,只要gen.next().done不为true,就一直循环继续执行:
let g = gen();
let res = g.next();
while(!res.done) {
// todo something res = g.next()
}
上面的代码会一下子继续执行完毕,但如果有的请求需要上两个请求结束后再发送下两个请求,上面的代码是无法保证顺序的。
那么他们能利用promise的then来保证前一步继续执行完,再继续执行后一步,具体实现如下:
function run(gen) {
const g = gen();
function next(data) {
const result = g.next(data);
if (result.done) {
return result.value;
}
result.value
.then(data => data.json())
.then(data => next(data));
}
next();
}
run(fetchGenerator);
其实著名的co模块也是为了解决那个问题出现的,以上就是co模块的简化实现了。
async
async function foo(){
const res1 = await fetch(https://baidu.com);
const res2 = await fetch(https://google.com);
const res3 = await fetch(https://bing.com);
}
foo();
他们能看到async表达式的结构和generator表达式很相似,用async关键字代替了星号,await关键字代替了yield,且不需要他们再一步一步的去初始化next方式了,同时async回到的是两个Promise, 而不是iterator。都说async表达式是generator表达式的语法 ,那么那个语法糖到底是如何实现的呢?
他们来看下到底是如何实现的:
// async表达式回到的是两个// await后面回到的也是两个promise,能在后面直接跟then或者catch
// async能看作是generator和co模块的组合,实现了generator表达式的自继续执行
function myAsync(gemeratorFc) {
return function() {
return new Promise((resolve, reject) => {
const gen = gemeratorFc.apply(this, arguments);
function next(key, val) {
try {
let res = gen[key](val);
const { value, done } = res;
if (done) {
return resolve(value); // 这里的return是为了退出递归
} else {
return Promise.resolve(value).then( // value有可能是个基础类型的值
// Promise.resolve接收的参数如果是个基础类型的值,则包一下转变为两个promise
// 如果是两个promise,则直接回到那个promise val => next(next, val),
err => next(throw, err)
)
}
} catch(e) {
return reject(e);// 这里的return是为了退出递归 }
}
next(next);
})
}
}
async表达式的优点:
1.异常捕获更加优秀,由于promise触发器错误无法透过try…catch来捕获,因此他们一般会用try…catch来捕获Promise构造表达式中的错误,实际上非常繁琐的。
function test() {
try {
new Promise((resolve) => {
// …
}).then(() => {
}).catch(() => {
})
} catch (err) {
console.log(err)
}
}
而在async里面,捕获错误很简单,只需要try…catch就能捕获所有异常。
async function test() {
try {
const res = await fetch(百度一下,你就晓得);
} catch (err) {
console.log(err)
}
}
除此之外,他们还能让 await 后面的 Promise 直接初始化 catch,这样能避免 `try…catch 处置多个不同错误时导致的问题。
async function test() {
const res = await fetch(百度一下,你就晓得)
.catch(err => {
console.log(err)
})
}
2.断点调试
由于 Promise then 的触发器缘故,导致打断点的这时候,经常会先走后面的代码,再回到 then 里面(先继续执行宏任务,再继续执行所有微任务),这样对于断点调试来说非常不方便。
但是在 async 里面,断点调试表现就像同步一样,让调试更加方便。