首页 > 解决方案 > 直接传递 process.stdout.write 与通过回调传递不同的输出?

问题描述

我不太确定为什么会这样,但是我写了以下内容:

const runScript = (cmd, args) => {
  return new Promise((res, rej) => {
    // spawn a new process
    const ls = spawn(cmd, args);

    ls.stdout.on("data", (data) => {process.stdout.write(data)});

    ls.stderr.on("data", (data) => {process.stderr.write(data)});

    ls.on("close", code => {
      console.log(`Command ${cmd} ${args} exited with code ${code}`);
      code === 0 ? res(code) : rej(code);
    });

    ls.on("error", code => {
      rej(code);
    });
  });
};

这工作正常。但我想我可以将.on("data")事件处理程序更改为直接传入 write 函数。所以我从

ls.stdout.on("data", (data) => {process.stdout.write(data)});

ls.stdout.on("data", process.stdout.write);

根据命令,重构版本(.write直接传递)或 EPIPE 都没有输出。我以为他们完全一样。这里到底发生了什么?我怀疑它与缓冲或process所指的内容有关。

标签: javascriptnode.js

解决方案


当您process.stdout.write作为参数传递时,它会读取 的值process.stdout.write并将函数指针传递给该write方法。然后,当ls.staout.on()稍后调用该方法时,它不受约束process.stdout并且无法正常工作。

相反,改为:

ls.stdout.on("data", process.stdout.write.bind(process.stdout));

并且,当它被调用时,它将正确地绑定到所需的对象。

有关如何在函数内部进行控制的摘要,请参阅如何在函数调用中设置 thisthis


作为一个更简单的示例,请参见:

class X {
    constructor(val) {
        this.val = val;
    }
    add(otherVal) {
       return this.val + otherVal;
    }
}

let x = new X(3);
let fn = x.add;
fn(5);               // doesn't work properly

可以正常工作的示例:

let x = new X(3);
x.add(5);       // obj.method() sets proper value of this to obj in the method

或者,如果您想传递该方法:

let x = new X(3);
let fn = x.add;
fn.call(x, 5);   // fn.call(x) artificially sets this to x inside the method

或这个:

let x = new X(3);
let fn = x.add.bind(x);  // creates stub function that calls method properly
fn(5);

这也不起作用,因为当fn(5)被调用时,没有绑定到x对象,所以当函数运行时,对方法this内部的引用add()将没有正确的值this并且它不会正常工作。

当此代码执行let fn = x.add时,它会获得一个指向该add方法的指针,但没有绑定到该x对象。那会丢失。然后,当你调用时fn(5),由于thisJavascript 中的值是根据函数的调用方式设置的,所以这只是一个普通的函数调用,所以this值设置为undefined(在严格模式下)或全局对象(在非严格模式下) . 在任何一种情况下,它都不是所需的x对象。为了使它成为x对象,它必须被调用,因为x.fn()值必须人为地设置一些其他方法,this例如 with或。 .apply().call().bind()

在上述情况下,由于您不控制函数的调用者(它被您无法控制的其他代码调用),因此.bind()是一个合适的解决方案。


推荐阅读