1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
這個 callback 函數的運作方式是基於 JavaScript **異步回調機制**讓我詳細解釋

## 回調函數的運作原理

### 1. 函數傳遞
```javascript
mqttClient.publish(topic, message, options, function(error) {
    // 這個函數被當作參數傳入
});
```
- 這個 `function(error)` 被當作**參數**傳給 `publish` 方法
- `publish` 方法會**保存**這個函數的引用

### 2. 異步執行流程
```javascript
// 1. 呼叫 publish,立即返回(不等待結果)
mqttClient.publish(topic, message, options, callback);

// 2. 程式繼續執行下一行(不會等待發送完成)
console.log("這行會立即執行");

// 3. 當發送完成後,MQTT 客戶端會呼叫 callback
```

### 3. 回調執行時機
MQTT 客戶端內部大概是這樣運作
```javascript
// MQTT 客戶端內部的邏輯(簡化版)
function publish(topic, message, options, callback) {
    // 發送訊息到 broker
    sendToBroker(topic, message, options)
        .then(() => {
            // 成功時呼叫 callback,error 參數為 null
            callback(null);
        })
        .catch((err) => {
            // 失敗時呼叫 callback,傳入錯誤物件
            callback(err);
        });
}
```

## 參數傳遞機制

### 成功情況
```javascript
// MQTT 客戶端內部呼叫:
callback(null);  // error 參數為 null

// 你的回調函數收到:
function(error) {
    if (error) {        // null 是 falsy,所以不會執行
        // 不會執行
    } else {
        console.log('成功');  // 會執行這裡
    }
}
```

### 失敗情況
```javascript
// MQTT 客戶端內部呼叫:
callback(new Error("連線逾時"));  // 傳入錯誤物件

// 你的回調函數收到:
function(error) {
    if (error) {        // Error 物件是 truthy
        console.error('失敗:', error);  // 會執行這裡
    } else {
        // 不會執行
    }
}
```

## 常見的回調模式

### Node.js 錯誤優先回調 (Error-first Callback)
```javascript
function(error, result) {
    if (error) {
        // 處理錯誤
    } else {
        // 使用 result
    }
}
```

### 你的例子是簡化版
```javascript
function(error) {
    // 只關心是否成功,不需要返回資料
}
```

## 實際執行範例
```javascript
console.log("1. 開始發送");

mqttClient.publish(topic, message, options, function(error) {
    console.log("3. 收到發送結果");
    if (error) {
        console.log("4. 發送失敗");
    } else {
        console.log("4. 發送成功");
    }
});

console.log("2. 繼續執行其他程式");

// 輸出順序:
// 1. 開始發送
// 2. 繼續執行其他程式
// 3. 收到發送結果
// 4. 發送成功/失敗
```

這就是為什麼叫做**異步**的原因 - 程式不會停下來等待結果而是透過回調函數在適當時機處理結果