Signatur
Beschreibung
USBOutTransferResult gehört zur WebUSB API. Instanzen erhält man als aufgelösten Wert der Promises, die USBDevice.prototype.transferOut() (Bulk- oder Interrupt-Transfer an einen OUT-Endpunkt) und USBDevice.prototype.controlTransferOut() (Steuertransfer an den Endpunkt 0) zurückgeben. Das Objekt meldet, ob der Transfer geklappt hat und wie viele Bytes das Gerät tatsächlich angenommen hat.
Das Interface hat zwei schreibgeschützte Eigenschaften:
bytesWritten– Anzahl der Bytes (number), die an das Gerät übertragen wurden. Sie kann kleiner als die Länge des gesendeten Puffers sein.status– Status des Transfers alsstring:"ok"bei Erfolg oder"stall", wenn das Gerät den Endpunkt blockiert hat (STALL). Den Wert"babble"gibt es in der AufzählungUSBTransferStatuszwar auch, er kommt aber nur bei eingehenden Transfers vor.
In der Praxis prüft man nach jedem Schreibvorgang status und vergleicht bytesWritten mit der erwarteten Länge. Bei "stall" muss der Endpunkt meist mit USBDevice.clearHalt() wieder freigegeben werden, bevor weitere Transfers möglich sind. Schwere Fehler, etwa ein getrenntes Gerät oder ein nicht beanspruchtes Interface, führen dagegen dazu, dass das Promise mit einer DOMException zurückgewiesen wird. Sie tauchen also nicht im status auf.
Einen Konstruktor gibt es auch, man braucht ihn aber selten. Mit new USBOutTransferResult(status, bytesWritten) lassen sich zum Beispiel Testattrappen (Mocks) oder Polyfills bauen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $status Pflicht | "ok" | "stall" | "babble" | Nur beim Konstruktor: der Transferstatus, der später über status ausgelesen wird. |
|
| $bytesWritten | number | 0 | Nur beim Konstruktor: die Anzahl der übertragenen Bytes, die später über bytesWritten ausgelesen wird. |
Rückgabewert
status (string) und bytesWritten (number). Man bekommt es als aufgelösten Wert von transferOut() bzw. controlTransferOut() oder über den Konstruktor.Beispiele
Daten per Bulk-Transfer senden und Ergebnis prüfen
// Muss durch eine Benutzeraktion ausgelöst werden (z. B. Klick)
const sendCommand = async () => {
const device = await navigator.usb.requestDevice({
filters: [{ vendorId: 0x2341 }]
});
await device.open();
if (device.configuration === null) await device.selectConfiguration(1);
await device.claimInterface(0);
const data = new TextEncoder().encode('LED ON\n');
const result = await device.transferOut(2, data); // Endpunkt 2 (OUT)
console.log(result instanceof USBOutTransferResult);
console.log(`Status: ${result.status}, gesendet: ${result.bytesWritten}/${data.byteLength}`);
};
document.querySelector('#send').addEventListener('click', sendCommand);
Steuertransfer (controlTransferOut) an das Gerät
const setLineCoding = async (device, baudRate = 115200) => {
// CDC-ACM: SET_LINE_CODING (Request 0x20)
const buffer = new ArrayBuffer(7);
const view = new DataView(buffer);
view.setUint32(0, baudRate, true); // Baudrate
view.setUint8(4, 0); // 1 Stoppbit
view.setUint8(5, 0); // keine Parität
view.setUint8(6, 8); // 8 Datenbits
const result = await device.controlTransferOut({
requestType: 'class',
recipient: 'interface',
request: 0x20,
value: 0x00,
index: 0x00
}, buffer);
if (result.status !== 'ok') {
throw new Error(`Steuertransfer fehlgeschlagen: ${result.status}`);
}
return result.bytesWritten;
};
STALL behandeln und unvollständige Übertragung erkennen
const writeAll = async (device, endpoint, data) => {
let offset = 0;
while (offset < data.byteLength) {
const chunk = data.subarray(offset);
const { status, bytesWritten } = await device.transferOut(endpoint, chunk);
if (status === 'stall') {
console.warn('Endpunkt blockiert – clearHalt() wird ausgeführt');
await device.clearHalt('out', endpoint);
continue; // erneut versuchen
}
offset += bytesWritten;
}
return offset;
};
Konstruktor für Unit-Tests (Mock-Gerät)
const mockDevice = {
transferOut: async (endpoint, data) =>
new USBOutTransferResult('ok', data.byteLength)
};
const result = await mockDevice.transferOut(1, new Uint8Array([1, 2, 3]));
console.log(result.status, result.bytesWritten);
const stalled = new USBOutTransferResult('stall');
console.log(stalled.status, stalled.bytesWritten);
// Wichtig · Fallstricke
- Browser-Unterstützung: WebUSB ist experimentell und nur in Chromium-basierten Desktop-Browsern (Chrome, Edge, Opera) sowie in Chrome für Android verfügbar. Firefox und Safari unterstützen die API nicht. Prüfe deshalb vorab mit
'usb' in navigator, ob sie vorhanden ist. - Nur in sicheren Kontexten: Die API läuft nur über HTTPS oder auf
localhost.navigator.usb.requestDevice()braucht eine Benutzeraktion und lässt sich per Permissions-Policyusbsperren, zum Beispiel in iframes. statusimmer prüfen: Ein aufgelöstes Promise heißt nicht automatisch, dass der Transfer erfolgreich war. Ein"stall"wird nicht als Ausnahme geworfen, sondern steht nur im Ergebnisobjekt.- Teilweise Übertragung:
bytesWrittenkann kleiner als die Pufferlänge sein. Vergleiche die Werte und sende den Rest bei Bedarf erneut. - Ausnahmen statt Status: Ist das Gerät getrennt, das Interface nicht beansprucht (
claimInterface()) oder die Endpunktnummer ungültig, wird das Promise mit einerDOMException(z. B.NotFoundError,InvalidStateError,NetworkError) zurückgewiesen. Nutze dafürtry/catch. - Das Interface ist auch in Dedicated Workern verfügbar.