【问题标题】:Node.js: Which parts of the code are executed following an asynchronous call?Node.js:代码的哪些部分在异步调用之后执行?
【发布时间】:2017-04-18 19:31:46
【问题描述】:

异步调用是 javascript 的固有部分,使用回调通常是处理这些调用的优雅工具。

但是,我不太确定异步操作之后的代码分支是如何决定的。例如,下面的代码会发生什么?

function f(callback) {
   value = some_async_call();
   if (value) {
       callback(value);
   }
   return(value);
}

这里会发生什么?根据我短暂的 JS 经验,return 会发回一个 undefined 值。但是假设value 从异步调用返回true,回调是用正确的值调用还是用undefined 值调用?

换句话说,关于哪些操作在异步调用之后立即执行,哪些操作被延迟到返回值时,是否有规则?

在询问之前我尝试过什么

SFTW 用于在 javascript 中分支异步调用,但没有发现任何规范或决定性。

【问题讨论】:

  • 我敢打赌,如果some_async_call 在执行if(value) 之前返回一些东西,那么它根本就不是一个异步任务。这样做的方法是,而不是测试任务的任何返回, 将你的回调传递给它(如果它是异步的,它肯定会为回调提供一个参数)。应该是some_async_call(callback); 而不是value = some_async_call();
  • some_async_call 是一个适当的异步函数,还是只是一个执行一些异步操作的函数?如果是后者,如果值依赖于异步调用,则无法真正返回值。

标签: javascript node.js asynchronous


【解决方案1】:

更新:在底部添加了 3 种不同方法之间的实际区别

假设some_async_call(); 被定义为异步函数:async function some_async_call() { ... }

这个函数返回的是一个Promise,这意味着value现在是一个promise:value.then( function(result) { } )

当我把它翻译成代码时:

async function some_async_call() { 
    if (theMoonIsInTheRightPosition)
        return Fetch('/api/data/') // this returns a promise as well.

    return false;
}

我现在可以做两件事:

function parentFunction(callback) {
    var promise = some_async_call();
    promise.then( callback );
    return ...; // you can't "return" the value of an async call synchronously, since it is a promise.
}

或:

async function asyncParentFunction( callback ) {
    var value = await some_async_call();
    if (value)
        callback( value );
    return value;
}

但是,这也将父函数转换为异步函数,这意味着该函数的直接返回值......也是一个承诺。

长话短说:

您可以使用回调来处理异步函数、promise 或 async/await

回调

function doStuff(callback) {
    // do asynchronous stuff
    var result = 100;
    callback(result); // once you're done with stuff
}
doStuff( function(data) { console.log('Im done!', data); } );

承诺

function doStuff() {
    return new Promise(function(resolve, reject) {
        // do asynchronous stuff
        var result = 100;
        resolve(result);
    });
}
doStuff.then(function(data) { console.log('Im done!', data); });

异步/等待

function doStuff() {
    return new Promise(function(resolve, reject) {
        // do asynchronous stuff
        var result = 100;
        resolve(result);
    });
}
(async function() { // async/await only works in async functions.
    var data = await doStuff();
    console.log('Im done!', data);
})();

如您所见:promise 和 async/await 使用相同的机制,非常值得一读。

三者区别的实际例子:

回调

function fetchUserWithPosts(userId, callback) {
    fetchUser(userId, function(user) {
        fetchPostsByUserId(userId, function(posts) {
            callback({
                user: user,
                posts: posts
            });
        });
    });
}

承诺

function fetchUserWithPosts(userId) {
    return Promise.all([
        fetchUser(userId),
        fetchPostsByUserId(userId)
    ]).then(function(result) {
        return {
            user: result[0],
            posts: result[1]
        };
    });
}

异步/等待

async function fetchUserWithPosts(userId) {
    return {
        user: await fetchUser(userId),
        posts: await fetchPostsByUserId(userId);
    };
}

【讨论】:

    【解决方案2】:

    你是对的,undefined 会被退回。您在异步操作之后执行您的逻辑,您应该将您的回调传递给该函数。您正在尝试以同步方式使用代码,async/await 来救援。假设 some_async_call returns Promise 你可以这样写:

    async function f(callback) {
      var value = await some_async_call();
      if (value) {
        callback(value);
      }
      return value;
    }
    

    在这种情况下,您的函数将返回 Promise 的值,并且也是异步的。阅读更多here

    您甚至不需要传递回调。您可以在客户端代码中 await 您的函数并从那里执行回调。

    关于分支,不使用async/await 进行分支的唯一方法是让some_async_call 接受一个接受value 作为参数的回调:

    function f(callback) {
     some_async_call(function(value) {
       if (value) {
         callback(value);
       }
     });
    }
    

    再次重申,除了Promise,没有办法从异步方法返回值。或Observable 中的RxJS

    【讨论】:

    • 谢谢。除了我的示例之外,在同步调用之后是否有关于代码流的一般规则?有没有关于分支的官方参考资料?
    • 异步函数类似于setTimeout。它会立即返回。唯一和执行将向前推进。在 Promisesasync/await 之前的异步操作之后获取值或执行逻辑的唯一方法是传递回调。如果这就是你的意思。
    • @AdamMatan,你可能也有兴趣阅读 node.js 中的控制流book.mixu.net/node/ch7.html
    猜你喜欢
    • 1970-01-01
    • 2013-02-02
    • 1970-01-01
    • 2017-09-20
    • 2019-10-20
    • 2018-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多