JS异步编程:从Generator到async/await的同步写法演进

作者:木棉时间:2026-10-24 23:48:30浏览:642

本文深入解析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同步内容,可搜索本站往期文章或继续浏览相关文章,感谢支持!

作者最新文章