节点正在等待已经终止的超时

node is waiting for a timeout that already killed

我设置了发回错误的超时时间。问题是,如果我需要用 clearTimeOut() 清除超时,它确实会杀死它,我可以看到,因为 errTimeout 的 _kill 的值在调试器中显示为 true。但出于某种原因,节点仍然保留 运行 脚本,直到 timeOutPeriod 结束。我想它不会真正在生产中产生问题,因为调用函数将接收返回值。但它一直在等待而不是终止脚本,这仍然让我很生气。

return new Promise((resolve,reject) => {
    function checkResponse () {
        //creates a timeout that returns an error if data not receieved after the specified time.
        let errTimeout = setTimeout(reject, config.timeOutPeriod);
        //the +1 is there because we originally reduced one, we need to use the physical number now.
        if(layerKeycodes.length !== (rows+1) * (columns+1)){
            //if the array is not complete, check again in 100 ms
            setTimeout(checkResponse, 100);
        } else {
            //clear the error timeout
            clearTimeout(errTimeout);
            //send the layerKeycodes to the calling function
            resolve(layerKeycodes);
        }
  }

看起来这段代码是您试图从这个 other question 中装入 getLayerKeycodes() 的代码,以便以某种方式知道何时从您的键盘硬件接收到所有数据。

我将说明如何在不使用计时器的情况下插入它。这是您在另一个问题中的开头:

你原来的函数

const getLayerKeycodes = (keyboard, layer, rows, columns) => {
    //array that stores all the keycodes according to their order
    let layerKeycodes = [];
    //rows and columns start the count at 0 in low level, so we need to decrease one from the actual number. 
    columns --;
    rows --;
    //loop that asks about all the keycodes in a layer
    const dataReceived = (err, data) => {
        if(err) {
            return err;
        }
        // push the current keycode to the array
        // The keycode is always returned as the fifth object.
        layerKeycodes.push(data[5]);
        console.log(layerKeycodes);
    };  
    for (let r = 0 , c = 0;c <= columns; r ++){
        //callback to fire once data is receieved back from the keyboard.
        if(r > rows){
            c++;
            //r will turn to 0 once the continue fires and the loop executes again 
            r = -1;
            continue;
        }
        //Start listening and call dataReceived when data is received 
        keyboard[0].read(dataReceived);
        //Ask keyboard for information about keycode
        // [always 0 (first byte is ignored),always 0x04 (get_keycode),layer requested,row being checked,column being checked]
        keyboard[0].write([0x01,0x04,layer,r,c]);
    }
    console.log(layerKeycodes);
}

手动创建承诺在完成所有 rows/columns

后解决

并且,您可以将完成检测代码合并到 dataReceived() 函数中,无需任何计时器,也无需像这样重新处理其余大部分逻辑:

const getLayerKeycodes = (keyboard, layer, rows, columns) => {
    return new Promise((resolve, reject) => {
            //array that stores all the keycodes according to their order
            const layerKeycodes = [];
            const totalCells = rows * columns;
            let abort = false;
            
            //rows and columns start the count at 0 in low level, so we need to decrease one from the actual number.
            columns--;
            rows--;

            // function that gets with keyboard data
            function dataReceived(err, data) => {
                if (err) {
                    abort = true;   // set flag to stop sending more requests
                    reject(err);
                    return;
                }
                // push the current keycode to the array
                // The keycode is always returned as the fifth object.
                layerKeycodes.push(data[5]);
                
                // now see if we're done with all of them
                if (layerKeycodes.length >= totalCells) {
                    resolve(layerKeycodes);
                }
            }

            // loop that asks about all the keycodes in a layer
            for (let r = 0, c = 0; c <= columns; r++) {
                // stop sending more requests if we've already gotten an error
                if (abort) {
                    break;
                }
                //callback to fire once data is receieved back from the keyboard.
                if (r > rows) {
                    c++;
                    //r will turn to 0 once the continue fires and the loop executes again
                    r = -1;
                    continue;
                }
                //Start listening and call dataReceived when data is received
                keyboard[0].read(dataReceived);
                //Ask keyboard for information about keycode
                // [always 0 (first byte is ignored),always 0x04 (get_keycode),layer requested,row being checked,column being checked]
                keyboard[0].write([0x01, 0x04, layer, r, c]);
            }
        }
    }
}

承诺读取功能的简化版

而且,这里有一个更简单的版本,它提供了读取功能,因此我们可以在其上使用 await,然后只需使用一个 async 函数和一个双重嵌套的 for 循环更简单的循环机制。

const util = require('util');

async function getLayerKeycodes(keyboard, layer, rows, columns) => {
    // promisify the keyboard.read()
    const readKeyboard = util.promisify(keyboard[0].read).bind(keyboard[0]);

    //array that stores all the keycodes according to their order
    const layerKeycodes = [];

    // loop that asks about all the keycodes in a layer
    for (let rowCntr = 0; rowCntr < rows; rowCntr++) {
        for (let colCntr = 0; colCntr < columns; colCntr++) {

            // Start listening and collect the promise
            const readPromise = readKeyboard();
            // Ask keyboard for information about keycode
            // [always 0 (first byte is ignored),always 0x04 (get_keycode),layer requested,row being checked,column being checked]
            keyboard[0].write([0x01, 0x04, layer, rowCntr, colCntr]);

            // wait for data to come in
            const data = await readPromise;

            // push the current keycode to the array
            // The keycode is always returned as the fifth object.
            layerKeycodes.push(data[5]);
        }
    }
    return layerCodes;
}

这也确保我们发送一个写入,然后等待该写入的数据返回,然后再发送下一个写入,这似乎是一种处理硬件的潜在更安全的方式。您的原始代码会立即触发所有可能有效的写入操作,但读取操作似乎可以按任何顺序返回。这保证了 layerCodes 数组中的顺序顺序,这看起来更安全(我不确定这是否与此数据有关)。

最后一个版本中的错误处理在某种程度上是由 async 函数和承诺自动处理的。如果读取 returns 一个错误,那么 readPromise 将自动拒绝,这将中止我们的循环并反过来拒绝异步函数返回的承诺。因此,我们不必 abort 检查具有手动创建的 promise 的先前函数是否具有。


现在,当然,我没有能力 运行 测试其中的任何一个,所以可能在某处有一些错别字,但希望你能完成其中的任何一个并看到这些工作原理的概念。