JS异步编程:从Generator到async/await的同步写法演进
本文深入解析JavaScript异步编程的演进,从Generator函数的状态机特性出发,详细演示如何通过yield和next传值实现异步操作的同步化书写。随后介绍基于Promise的封装方案,最终引出ES6标准的async/await语法,展示其作为Generator语法的语法糖本质,帮助开发者掌握更简洁高效的异步处理技巧。
异步操作的同步化思路
首先假设存在一个名为readFile的方法,用于读取文件内容,该方法执行异步操作。
var gen = function* (){
var a = yield readFile('./a.txt');
console.log(a.toString());
var b = yield readFile('./b.txt');
console.log(b.toString());
};对比上述代码,若将function关键字后的星号(*)替换为async,并将yield替换为await,即可得到如下代码形式。
var gen = function async (){
var a = await readFile('./a.txt');
console.log(a.toString());
var b = await readFile('./b.txt');
console.log(b.toString());
};Generator函数的状态机原理
这种写法实现了以同步语法执行异步操作的效果。第一种实现方式依赖于ES6引入的Generator函数。从语法角度理解,Generator函数可被视为封装了多个内部状态的状态机。执行该函数会返回一个遍历器对象,因此它既是状态机,也是遍历器对象的生成器。返回的遍历器对象能够依次遍历Generator函数内部的各个状态。若对上述官方解释感到困惑,可通过后续示例进行直观演示。
function* func(){
console.log("one");
yield '1';
console.log("two");
yield '2';
console.log("three");
return '3';
}
var f = func();
f.next(); // one // {value: "1", done: false}
f.next(); // two // {value: "2", done: false}
f.next(); // three // {value: "3", done: true}
f.next(); // {value: undefined, done: true}在首次调用f.next()时,func函数开始执行,并在遇到第一个yield语句时暂停,返回yield后表达式的值,格式为{value: "1", done: false}。其中,value表示yield表达式的值,done表示函数是否执行完毕。若继续调用f.next(),将依次返回后续yield表达式的值,如{value: "2", done: false}。持续调用f.next()直至done变为true,表明func函数执行结束。
function* func(){
var a = yield '1';
console.log(a);
var b = yield '2';
console.log(b);
}
var f = func();
f.next();
f.next('1'); 基于Promise的异步封装实现
通过f.next('2')继续改造func函数,在next方法中分别传入1和2,此时console.log(a)将打印1,console.log(b)将打印2,证明可以向Generator函数内部传值。基于此原理,重新设计并实现readFile函数。
var gen = function* (){
var a = yield readFile('./a.txt');
console.log(a.toString());
var b = yield readFile('./b.txt');
console.log(b.toString());
};
var readFile = function (fileName){
return new Promise((resolve)=>{
fs.readFile(fileName, (err, data)=>{
resolve(data);
})
});
};
function run(fn) {
var gen = fn();
function next(data) {
var result = gen.next(data);
if (result.done) return;
result.value.then((data)=>{
next(data);
})
}
next();
}
run(gen);async/await语法糖本质
使用Promise实现readFile函数,此时yield的返回值即为Promise对象。通过esult.value.then((data)=>{next(data);})将yield返回的value值重新传回Generator函数,使得console.log(a.toString())能够获取a.txt文件的内容。利用if (result.done) return;判断Generator函数是否执行完毕,从而结束循环调用。单独观察gen函数,可见其实现了异步操作的同步语法书写。若将function后的*改为async,yield改为await,即得到常用的语法形式。
至此,关于JS异步编程中async和await实现同步写法的介绍完成。如需了解更多js async和await同步内容,可搜索本站往期文章或继续浏览相关文章,感谢支持!
JavaScript怎么准确判断数据类型:typeof、instanceof与Object.prototype.toString
2026-11-05 17:09:21
JS中将数组和对象混合组装为JSON字符串
2026-11-05 16:41:42
JS运算符优先级与结合性的区别是什么?
2026-11-05 13:22:02
JS Map怎么只遍历Key或Value
2026-11-05 13:00:36
D3.js 与 ECharts 选型对比:灵活性 vs 开发效率
2026-11-05 09:45:01
