【问题标题】:Determine whether a method is synchronous or asynchronous判断一个方法是同步的还是异步的
【发布时间】:2012-09-22 17:09:45
【问题描述】:

在node.js中,是否可以(使用函数)判断一个方法是同步的还是异步的?

我想编写一个执行以下操作的函数:

function isSynchonous(methodName) {
    //if the method is synchronous, return true. Otherwise, return false.
}

【问题讨论】:

标签: javascript node.js


【解决方案1】:

不,那是不可能的。这些方法不仅标记为同步或异步,它们要么使用回调,要么不使用。

【讨论】:

  • 我不明白为什么这是不可能的。我可以尝试检查方法的源代码;这会表明该方法是否是同步的吗?
  • 另外,Javascript中的“同步函数”和“异步函数”是否有明显的区别,或者一个函数在不同的用例中可以是同步的还是异步的?
  • @AndersonGreen:不幸的是,检查方法的源代码以确定它是否异步等同于解决停止问题,并且无论如何都没有意义。不,同步函数和异步函数之间没有明显的区别。不同之处在于它们可能会接受回调并异步调用它。他们也可以同步调用它。两者混合在一起 - 一个调用异步操作的同步操作。一些函数会根据回调的存在自动决定。异步性不是语言特性。
  • 请注意,混合同步/异步是邪恶的。如果它是同步的,它仍然应该发生在process.nextTick
  • @djechlin:这适用于 I/O;计算阶乘怎么样?这取决于。
【解决方案2】:

你不一定知道。一个函数甚至可以是随机同步或异步的。

例如,一个接受另一个函数的函数可以立即执行该函数,或者它可以使用 setImmediate 或 nextTick 安排在以后执行它。该函数甚至可以随机选择同步或异步调用其传递的函数,例如:

console.log('Start')

function maybeSynchOrAsync(fun) {

  var rand = Math.floor((Math.random() * 2))

  if (rand == 0) {
    console.log('Executing passed function synchronously')
    fun()
    console.log('Done.')
  } else {
    console.log('Executing passed function asynchronously via setImmediate')
    setImmediate(fun)
    console.log('Done.')
  }
}

maybeSynchOrAsync(function () { console.log('The passed function has executed.') });

此外,从技术上讲,每个函数调用都是同步的。如果你调用一个函数 F,而 F 将一个回调函数排队等待稍后调用(使用 setTimeout 或任何机制),原始函数 F仍然有一个同步的返回值(无论是未定义的、promise、thunk 还是其他)。

【讨论】:

    【解决方案3】:

    从语言的角度来看,这是不可能的,我相信 llambda 的回答证明了这一点。

    • 函数可以异步执行但同步返回;比如说,返回被触发的异步任务的数量。
    • 函数可以同步返回代表异步信息的承诺。我会称这种方法为异步方法,但语言无法真正说明这一点。
    • 在某种反常的意义上,每个异步函数都会“返回”一些东西...undefined,如果没有别的。

    从工程的角度来看:

    • 阅读文档。
    • 如果函数接受回调,它很可能是异步的。查看函数签名。
    • 阅读代码。
    • 使用“常识”。如果函数执行 IO 并从 IO 返回结果,则在某些情况下,它必须是异步的。这包括文件读取、从标准输入读取、保存到数据库和 HTTP/AJAX 请求。 Note 流通常用于此,它表示异步任务,但回调是特殊的。

    此外,还有 函数将两者混合在一起。

    function(callback) {
        if(ready) {
            callback();
        }
        else {
            setTimeout(callback, 5000);
        }
    }
    

    可以说这是非常邪恶的,正确的做法应该是

    if(ready) {
        process.nextTick(callback);
    }
    

    所以函数具有统一的行为。

    不过, 是一种很老套的方法来判断是否发生了异步事件,至少在 Node.js 中是这样。见this discussion

    // untested!! please read the documentation on these functions before using yourself
    var work = process._getActiveHandles().length + process._getActiveCallbacks().length;
    foo;
    var newWork = (process._getActiveHandles().length + process._getActiveCallbacks().length) - work;
    if(newWork > 0) {
        console.log("asynchronous work took place.");
    }
    

    这是因为异步工作不能在同一个刻度上解决,根据定义,并且因为 Node.js 是单线程的。

    【讨论】:

      【解决方案4】:

      为什么你需要知道,才是真正的问题。

      话虽如此;这可以通过新的 JS 抽象来实现。现在,对于由前面的 async 关键字明确定义的异步函数,您可以执行类似的测试;

      async function test(){}
      var type = Object.getPrototypeOf(test).constructor.name;
      console.log(type); // <- 'AsyncFunction'
      

      酷..!

      对于那些碰巧返回一个promise的普通函数,我们必须记住它只是一个同步函数立即同步返回一个promise对象。这意味着您必须在调用函数之前动态检查函数是否提前返回承诺。我认为这将带您进入类型级别的编程冒险,这种冒险存在于 Haskell 等复杂语言中。

      【讨论】:

      • 我在几年前(2012 年)发布了这个问题,当时 JavaScript 的这个功能还不存在。
      • @AndersonGreen 是的,当然 :) 我只是认为您的问题是一个很好的问题并且仍然有效,因此为了完整性而放置了一个答案。
      猜你喜欢
      • 2020-05-15
      • 2020-02-21
      • 2013-02-25
      • 2012-12-30
      • 2014-04-25
      • 1970-01-01
      • 1970-01-01
      • 2020-03-05
      • 2019-01-17
      相关资源
      最近更新 更多