【问题标题】:Is the following code asynchronous?下面的代码是异步的吗?
【发布时间】:2025-12-08 08:50:01
【问题描述】:

在阅读(强烈推荐)系列丛书You Don't Know JS 时,我阅读了this 部分:

function foo(x,y,cb) {
    ajax(
        "http://some.url.1/?x=" + x + "&y=" + y,
        cb
    );
}

foo( 11, 31, function(err,text) {
    if (err) {
        console.error( err );
    }
    else {
        console.log( text );
    }
} );

如您所见,foo 函数的调用完全由 wiki definition 异步:

异步,在计算机编程中,是指独立于主程序流程的事件的发生以及处理此类事件的方式。这些可能是“外部”事件,例如信号的到来,或由程序发起的与程序执行同时发生的动作,程序不会阻塞以等待结果 .

作者使用generators重新实现了上面的代码来演示当我们要执行异步函数时如何使用generators

function foo(x,y) {
    ajax(
        "http://some.url.1/?x=" + x + "&y=" + y,
        function(err,data){
            if (err) {
                // throw an error into `*main()`
                it.throw( err );
            }
            else {
                // resume `*main()` with received `data`
                it.next( data );
            }
        }
    );
}

function *main() {
    try {
        var text = yield foo( 11, 31 );
        console.log( text );
    }
    catch (err) {
        console.error( err );
    }
}

var it = main();

// start it all up!
it.next();

通过调用it.next(),我们执行main直到第一个yield,然后等到迭代器it将恢复main的执行。根据异步的定义,下面这段代码的调用不是异步的:

function *main() {
    try {
        var text = yield foo( 11, 31 );
        console.log( text );
    }
    catch (err) {
        console.error( err );
    }
}

还有:

var it = main();

// start it all up!
it.next();

我的任何结论都不正确吗?

【问题讨论】:

  • 那个代码不好
  • 我可以看到一个优势:这是最简洁的代码,可以将回调结果提取回调用者,而无需注册更多事件以使用该结果。
  • @Isaac After reading that chapter,我可以说这段代码非常强大,是实现asyncawait的第一步。我鼓励您阅读本章,以更好地了解这段代码如何演变为更加坚实和强大的东西。
  • 你正在使用一个全局变量it,这违背了试图解开你的代码的目的
  • 我也这么认为。但后来他慢慢地(一步一步地)将这段代码升级到更好的代码。

标签: javascript asynchronous generator


【解决方案1】:

我是 YDKJS 的作者。第一个运行的it.next() 调用,即第二个sn-p 的最后一行的调用,确实是同步,但文本并没有声明其他。相反,就像在第一个引用的 sn-p 中一样,文本断言第二个 it.next(..) 调用是异步的。

代码假设ajax(..) 调用实际上是异步调用,因此它的响应(调用该回调)也是异步的。因此,it.next(..) 的第二次调用——恢复暂停的yield foo(..) 调用的调用——在回调内部,实际上是异步发生的。

换句话说,yield foo(..) 会在本地暂停该生成器,而 Ajax 调用会处理,这允许任何其余 JS 程序运行,当 Ajax 响应返回时,it.next(..) 调用会恢复生成器...异步。

希望能解决问题。

【讨论】:

  • 感谢您的快速回答。这非常有帮助。建议阅读此问题的人在it.next(); 之后打印一些内容,并看到它会在所有内容之前打印出来;代码是完全异步的。