浏览器解决异步的发展史
- 回调
- promise
- generator
- async+await
generator
function * demo() {
// generator函数可以使用try...catch...
try {
let a = yield 1;
let b = yield 2;
}catch{
throw()
}
}
let it = demo(); // generator函数返回一个Generator对象
// 常用的Generator对象上的方法,next,throw
let {value, done} = it.next(); // 返回一个对象{value, done}
// it.next可以传递参数,但是第一次传递是没有意义的,每次执行到yield就会中断代码的执行,it.next返回的value可以传递给上一个yield的返回值
value = it.next(value).value
generator核心源码
- 用户调用generator方法时,内部对这个函数进行包装
- 调用regeneratorRuntime.mark函数,传递用户的generator函数作为参数,该函数把源函数返回
- 包装函数返回一个对象,包含next方法
- regeneratorRuntime.wrap(接受一个上下文为参数的函数, mark函数的返回值)
class Context {
constructor() {
this.next = 0;
this.done = false;
}
stop() {
this.done = true;
}
}
let regeneratorRuntime = {
mark(genFunc) {
return genFunc;
},
wrap(innerFn) {
let it = {};
let context = new Context();
it.next = function (v) {
context.sent = v; // 保留之前的值
let value = innerFn(context)
return {
value,
done
}
}
return it
}
}
var _marked = regeneratorRuntime.mark(read); // read就是刚才写的generator
function read() {
var a, b, c;
return regeneratorRuntime.wrap(
function read$(_context) {
while (1) { // 表示此方法 不止走一次, while(1) 表示这是一个状态机
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return 1;
case 2:
a = _context.sent;
console.log(a);
_context.next = 6;
return 2;
case 6:
b = _context.sent;
console.log(b);
_context.next = 10;
return 3;
case 10:
c = _context.sent;
console.log(c);
case 12:
case "end":
return _context.stop();
}
}
}, _marked);
}
co库
https://github.com/tj/co
,点击查看
function co(it) {
return new Promise((resolve, reject) => {
next();
function next(val) {
let {value, done} = it.next(val);
if (done) {
resolve(value)
} else {
Promise.resolve(value).then(data => {
next(data);
})
}
}
})
}
async+await
- async+await是generator+co的语法糖
- 底层还是异步的
let fs = require('fs').promises;
async function readAge(filePath) {
let name = await fs.readFile(filePath, 'utf8');
let age = await fs.readFile(name, 'utf8');
return age;
}
readAge('./name.txt').then(data => {
console.log(data);
})