用 jsdoc 记录回调的正确方法是啥?

Posted

技术标签:

【中文标题】用 jsdoc 记录回调的正确方法是啥?【英文标题】:What's the proper way to document callbacks with jsdoc?用 jsdoc 记录回调的正确方法是什么? 【发布时间】:2014-08-04 13:58:34 【问题描述】:

我花了很长时间在互联网上寻找使用 jsdoc 正确记录回调的最佳方法,但不幸的是,我还没有找到一个很好的方法。

这是我的问题:

我正在为开发人员编写一个 Node.js 库。该库提供了开发人员将使用的多个类、函数和方法。

为了使我的代码清晰易懂,以及(希望)将来自动生成一些 API 文档,我已经开始在我的代码中使用 jsdoc 来自我记录正在发生的事情。

假设我定义了如下函数:

function addStuff(x, y, callback) 
  callback(x+y);
);

使用jsdoc,我目前正在记录这个函数如下:

/**
  * Add two numbers together, then pass the results to a callback function.
  *
  * @function addStuff
  * @param int x - An integer.
  * @param int y - An integer.
  * @param function callback - A callback to run whose signature is (sum), where
  *  sum is an integer.
  */
function addStuff(x, y, callback) 
  callback(x+y);
);

我觉得上述解决方案有点 hack-ish,因为我无法绝对指定回调函数应该接受什么。

理想情况下,我想做这样的事情:

/**
  * Add two numbers together, then pass the results to a callback function.
  *
  * @function addStuff
  * @param int x - An integer.
  * @param int y - An integer.
  * @param callback callback - A callback to run.
  * @param int callback.sum - An integer.
  */
function addStuff(x, y, callback) 
  callback(x+y);
);

以上内容似乎可以让我更简单地传达我的回调需要接受的内容。这有意义吗?

我想我的问题很简单:用 jsdoc 清楚地记录我的回调函数的最佳方法是什么?

感谢您的宝贵时间。

【问题讨论】:

How to document callbacks using JSDoc?的可能重复 【参考方案1】:

JSDoc 3 有一个 @callback tag 就是为了这个目的。这是一个用法示例:

/**
 * Callback for adding two numbers.
 *
 * @callback addStuffCallback
 * @param int sum - An integer.
 */

/**
 * Add two numbers together, then pass the results to a callback function.
 *
 * @param int x - An integer.
 * @param int y - An integer.
 * @param addStuffCallback callback - A callback to run.
 */
function addStuff(x, y, callback) 
  callback(x+y);

【讨论】:

Visual Studio IDE 不支持此功能。这里的另一个答案,@param function(int):void callback 在 VS 中工作,也更简洁。 这是我最终在 Visual Code 中所做的。 如果这是一个添加两个数字的回调,回调应该有两个参数。我相信我们希望回调行说 callback(x,y) 并在回调文档字符串中添加另一个 @param。 @johnklawlor,我不这么认为。这是对 OP 的简化。当他的库完成处理可能更早在其他地方获得的两个数字时,但在本例中是通过他的addStuff 方法,通过调用客户端提供的callback 函数将结果返回给客户端。这个问题的目的是让客户端、库的用户清楚地知道回调函数应该有哪些参数。客户端将拥有一个任意名称的函数:function addStuffResult( res ) /* do stuff with res */ 【参考方案2】:

另一种可能性是这样描述传递给回调的值:

/**
  * Add two numbers together, then pass the results to a callback          function.
  *
  * @function addStuff
  * @param int x - An integer.
  * @param int y - An integer.
  * @param function(int) callback - A callback to run whose signature is (sum), where
  *  sum is an integer.
  */
function addStuff(x, y, callback) 
    callback(x+y);
);

要记录回调的返回类型,请使用@param function(int):string

【讨论】:

我喜欢这种方法,因为我的 IDE (Netbeans) 支持它,但似乎无法识别 @callback 标记 包含function(int)的返回值怎么样? @Maslow function(int):string(例如)在 Visual Studio Code 中为我工作。 刚刚发现使用@param function(error):void callback - Returns null if no error occurred. 有效,但它显示“arg0: any”。 error 必须是 Error 以便 Visual Studio Code 在测试后显示正确的输入。我不明白的是我读过很多帖子和问题,说类型在编写类型时不区分大小写。在使用 number 测试 javascript 之后,小写应该适用于原始类型。只是想我只是注意到这一点,以防其他人遇到同样的问题。 @Nova Error 不是原始类型?【参考方案3】:

让 VSCode 理解它的解决方法

/**
 * @typedef function(FpsInfo) fpsCallback
 * @callback fpsCallback
 * @param FpsInfo fps Fps info object
 */

 /**
 * @typedef Object FpsInfo
 * @property number fps The calculated frames per second
 * @property number jitter The absolute difference since the last calculated fps
 * @property number elapsed Milliseconds ellapsed since the last computation
 * @property number frames Number of frames since the last computation
 * @property number trigger Next computation will happen at this amount of frames
 */

/**
 * FPS Meter - Returns a function that is used to compute the framerate without the overhead of updating the DOM every frame.
 * @param fpsCallback callback Callback fired every time the FPS is computed
 * @param number [refreshRate=1] Refresh rate which the fps is computed and the callback is fired (0 to compute every frame, not recommended)
 * @returns function Returns a function that should be called on every the loop tick
 * @author Victor B - www.vitim.us - github.com/victornpb/fpsMeter
 */
function createFpsMeter(callback, refreshRate = 1) 
    // ...

【讨论】:

【参考方案4】:

可能我迟到了这个答案......但这是我的贡献。使用 ES6 我们可以做到这一点:

    /**
 *
 * @param import('../clients') clients  
 */
export default function socketServer(clients) 
io.on('connection', (webClient) => 


    webClient.on('register', (data) => 
      clients.add(data, webClient);
    );


 server.listen(8081, function (err) 
    if (err) throw err;
    console.log('listening on port 8081');
  );

)

在“clients”文件夹中,我们有一个包含此代码的 index.js 文件

let clients = new Map();

/**
 * Add Client to Collection
 * @param string key
 * @param object client
 */
export function add(key, client) 
  clients.set(key, client);

/**
 * Remove Client from Collection
 * @param string key
 */
export function remove(key) 
  clients.delete(key);


export const size = () => clients.size;

因此,在文件 /clients/index.js 中导出的所有函数都可以作为 JsDOC 使用,您可以通过 IntelliSense 引用它们

【讨论】:

【参考方案5】:
@param function(number):void myCallback

截至 2021 年,在 VS Code 和 WebStorm 中运行良好

【讨论】:

但是JSDoc没有官方支持,是吗?我在 jsdoc.app 上找不到任何此类示例。

以上是关于用 jsdoc 记录回调的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

让 JSDoc 正确记录嵌套闭包

如何使用 JSDoc 记录符号索引签名以符合打字稿?

如何使用 JSDoc 记录 CoffeeScript 源代码?

在 TypeScript 和/或 JSDoc 中,如何指示记录类型中的某些属性名称是同一类型中兄弟属性的别名?

类型擦除成员函数指针的“正确”方法是啥?

使用 JSDoc 记录私有构造函数