首页 > 解决方案 > 在异步函数内部生成 NodeJS 工作线程不遵守承诺解决方案

问题描述

我有一个异步函数,可以像这样启动 NodeJS 工作线程:

    encode : async (config) => {

      if (isMainThread) {

            const encode_worker = new Worker(`./service-encode.js`, { workerData: config });

            encode_worker.on('message', (transcode_data) => { 
              log.info("%o", transcode_data);
              return transcode_data;
            });

            encode_worker.on('error', (err) => { log.error(err)});
            encode_worker.on('exit', (code) => {
              if (code !== 0)
                throw new Error(`Encoding stopped with exit code [ ${code} ]`);
                console.log("* * * EXITED ENCODER WORKER * * *")

            });

      }

    },

serivce-encode.js文件中,我有以下使用异步函数的代码。请注意,我postMessage用来表示它已完成。

var transcoder        = require('./transcoder');

const {Worker, isMainThread, parentPort, workerData} = require('worker_threads');

console.log("* * * STARTING ENCODE THREAD * * *\n");
console.log(workerData);

transcoder.run(workerData)
          .then((results) => {
              transcode_data = results;
              parentPort.postMessage(transcode_data);
          })
          .catch(err => { throw err });

然后,我使用下面的示例代码,但'message'上面事件中的代码会立即触发。也就是说,它似乎没有等到它完成:

encode(conf).then((encode_data) => { console.log("Encode Data :", encode_data); 

encode函数工作正常,但该console.log语句在调用 encode() 函数时立即执行 - encode_datavar 也是undefined. 既然returnencode中的语句是在message事件中,那async函数的promise不应该在那个时候解决吗?

标签: javascriptnode.jsnode-worker-threads

解决方案


所以,你的async函数中的代码没有任何东西支持 Promise。您不能只是在async函数中抛出随机异步(但不是基于承诺的)代码并期望任何东西都能正常工作。一个async函数可以很好地与基于 Promise 的异步函数一起工作await。否则,它对那里的异步操作一无所知。这就是为什么调用encode()立即返回而不等待任何完成的原因。

另外,return transcode_data是在一个异步回调里面。在该回调中返回只是返回到调用回调的系统代码并被尽职地忽略。您不会从async函数本身返回任何内容。您正在返回该回调。

由于您的操作不是基于 Promise 的,因此要解决此问题,您必须通过将其包装在 Promise 中来使其基于 Promise,然后在需要时使用适当的值手动解决或拒绝该 Promise。你可以这样做:

encode: (config) => {

    if (isMainThread) {

        return new Promise((resolve, reject) => {
            const encode_worker = new Worker(`./service-encode.js`, { workerData: config });

            encode_worker.on('message', (transcode_data) => {
                log.info("%o", transcode_data);
                resolve(transcode_data);
            });

            encode_worker.on('error', (err) => {
                log.error(err)
                reject(err);
            });

            encode_worker.on('exit', (code) => {
                if (code !== 0) {
                    reject(new Error(`Encoding stopped with exit code [ ${code} ]`));
                }
                console.log("* * * EXITED ENCODER WORKER * * *")
            });

        });


    } else {
        // should return a promise from all calling paths
        return Promise.reject(new Error("Can only call encode() from main thread"));
    }

},

仅供参考,此代码假定您在此处从承诺中寻找的“结果”是transcode_data您从该工作人员那里获得的第一个结果message


推荐阅读