* Invoke a remote method asynchronously. * @param {string} method Method to invoke * @param {any[]} [transferList] Objects in `args` to be transferred * @param {any[]} args Arguments to pass to `method` * @returns {Promise }
(method, transferList, ...args)
| 565 | * @returns {Promise<any>} |
| 566 | */ |
| 567 | async makeAsyncRequest(method, transferList, ...args) { |
| 568 | this.waitForWorker(); |
| 569 | |
| 570 | MessageChannel ??= require('internal/worker/io').MessageChannel; |
| 571 | const asyncCommChannel = new MessageChannel(); |
| 572 | |
| 573 | // Pass work to the worker. |
| 574 | debug('post async message to worker', { method, args, transferList }); |
| 575 | const finalTransferList = [asyncCommChannel.port2]; |
| 576 | if (transferList) { |
| 577 | ArrayPrototypePushApply(finalTransferList, transferList); |
| 578 | } |
| 579 | this.#worker.postMessage({ |
| 580 | __proto__: null, |
| 581 | method, args, |
| 582 | port: asyncCommChannel.port2, |
| 583 | }, finalTransferList); |
| 584 | |
| 585 | if (this.#numberOfPendingAsyncResponses++ === 0) { |
| 586 | // On the next lines, the main thread will await a response from the worker thread that might |
| 587 | // come AFTER the last task in the event loop has run its course and there would be nothing |
| 588 | // left keeping the thread alive (and once the main thread dies, the whole process stops). |
| 589 | // However we want to keep the process alive until the worker thread responds (or until the |
| 590 | // event loop of the worker thread is also empty), so we ref the worker until we get all the |
| 591 | // responses back. |
| 592 | this.#worker.ref(); |
| 593 | } |
| 594 | |
| 595 | let response; |
| 596 | do { |
| 597 | debug('wait for async response from worker', { method, args }); |
| 598 | await AtomicsWaitAsync(this.#lock, WORKER_TO_MAIN_THREAD_NOTIFICATION, this.#workerNotificationLastId).value; |
| 599 | this.#workerNotificationLastId = AtomicsLoad(this.#lock, WORKER_TO_MAIN_THREAD_NOTIFICATION); |
| 600 | |
| 601 | response = receiveMessageOnPort(asyncCommChannel.port1); |
| 602 | } while (response == null); |
| 603 | debug('got async response from worker', { method, args }, this.#lock); |
| 604 | |
| 605 | if (--this.#numberOfPendingAsyncResponses === 0) { |
| 606 | // We got all the responses from the worker, its job is done (until next time). |
| 607 | this.#worker.unref(); |
| 608 | } |
| 609 | |
| 610 | const body = this.#unwrapMessage(response); |
| 611 | asyncCommChannel.port1.close(); |
| 612 | return body; |
| 613 | } |
| 614 | |
| 615 | /** |
| 616 | * Invoke a remote method synchronously. |
no test coverage detected