首頁 web前端 js教程 詳解從Node.js的child_process模組來學習父子進程之間的通訊的範例程式碼

詳解從Node.js的child_process模組來學習父子進程之間的通訊的範例程式碼

Mar 28, 2017 pm 02:51 PM

這篇文章主要介紹了從Node.##js的child_process模組來學習父子進程之間的通信,具有一定的參考價值,有興趣的小夥伴可以參考一下。 ,這個功能主要是透過child_process.spawn函數

來提供的:

const spawn = require('child_process').spawn; 
const ls = spawn('ls', ['-lh', '/usr']); 
ls.stdout.on('data', (data) => { 
 console.log(`stdout: ${data}`); 
}); 
ls.stderr.on('data', (data) => { 
 console.log(`stderr: ${data}`); 
}); 
ls.on('close', (code) => { 
 console.log(`child process exited with code $[code]`); 
});
登入後複製
登入後複製
預設情況下,Node.js進程和子進程之間的stdin,stdout,stderr管道是已經存在的。進程的資料可能不會馬上消費)。

循環

,然而child-process.spawnSync方法是同步的,他會阻塞事件循環只到產生的程序退出或終止。一個shell客戶端,然後使用shell來執行程序,當完成的時候傳遞給
回調函數

一個stdout和stderr

child_process.execFile:和exec相似,但是他不會馬上產生一個shell
child_process.fork:產生一個新的Node.js進程,同時執行一個特定的模組來產生IPC通道,進而在父進程和子進程之間傳輸資料

child_process.execSync:和exec不同之處在於會阻塞Node.js的事件循環,然而child-process

child_process.execFileSync:和execFile不同之處在於會阻塞Node.js的事件循環,然而child-process在某些特殊情況下,例如自動化shell腳本,同步的方法可能更有用。迴圈


child_process.spawn(), child_process.fork(), child_process.exec(), and child_process.execFile()都是非同步的

API
。每一個方法都會產生一個ChildProcess實例,而且這個

物件

實作了Node.js的EventEmitter這個API,於是父行程可以註冊監聽函數,在子行程的特定事件觸發的時候被呼叫。 child_process.exec() 和 child_process.execFile()可以指定一個可選的callback函數,這個函數在子程序終止的時候被呼叫。


在windows平台上執行.bat和.cmd:

child_process.exec和child_process.execFile的差異可能隨著平台不同而有差異。在Unit/Linux/OSX平台上execFile更有效率,因為他不會產生shell。在windows上,.bat/.cmd在沒有終端的情況下是無法執行的,因此就無法使用execFile(child_process.spawn也無法使用)。在window上,.bat/.cmd可以使用spawn方法,同時指定一個shell選項;或者使用child_process.exec或透過產生一個cmd.exe同時把.bat/.cmd檔傳遞給它作為參數(child_process.exec就是這麼做的)。

const spawn = require('child_process').spawn; 
const bat = spawn('cmd.exe', ['/c', 'my.bat']);//使用shell方法指定一个shell选项 
bat.stdout.on('data', (data) => { 
 console.log(data); 
}); 
bat.stderr.on('data', (data) => { 
 console.log(data); 
}); 
 
bat.on('exit', (code) => { 
 console.log(`Child exited with code $[code]`); 
});
登入後複製

或也可以使用以下的方式:

const exec = require('child_process').exec;//产生exec,同时传入.bat文件 
exec('my.bat', (err, stdout, stderr) => { 
 if (err) { 
  console.error(err); 
  return; 
 } 
 console.log(stdout); 
});
登入後複製
child_process.exec(command[, options][, callback])

#其中options中的maxBuffer參數表示stdout/stderr允許的最大的資料量,如果超過了資料量那麼子程序就會被殺死,預設是200*1024位元;killSignal預設是'SIGTERM'。其中回呼函數當行程結束時候調用,參數分別為error,stdout,stderr。這個方法回傳的是一個ChildProcess物件。

const exec = require('child_process').exec; 
const child = exec('cat *.js bad_file | wc -l', 
 (error, stdout, stderr) => { 
  console.log(`stdout: ${stdout}`); 
  console.log(`stderr: ${stderr}`); 
  if (error !== null) { 
   console.log(`exec error: ${error}`); 
  } 
});
登入後複製

上面的程式碼產生一個shell,然後使用這個shell執行指令,同時對產生的結果進行快取。其中回呼函數中的error.code屬性表示子進程的exit code,error.signal表示結束這個進程的訊號,任何非0的程式碼表示出現了錯誤。預設的options參數值如下:

{ 
 encoding: 'utf8', 
 timeout: 0, 
 maxBuffer: 200*1024,//stdout和stderr允许的最大的比特数据,超过她子进程就会被杀死 
 killSignal: 'SIGTERM', 
 cwd: null, 
 env: null 
}
登入後複製

如果timeout非0,那麼父進程就會發送訊號,這個訊號透過killSignal指定,預設是"SIGTERM"來終結子行程,如果子行程超過了timeout指定的時間。注意:和POSIX系統上呼叫exec方法不一樣的是,child_process.exec不會取代目前線程,而是使用一個shell去執行指令

child_process.execFile(file[, args][ , options][, callback])

其中file表示需要執行的檔案。 child_process.execFile()和exec很相似,但是這個方法不會產生一個shell。指定的可執行檔會馬上產生一個新的線程,因此其效率比child_process.exec高。

const execFile = require('child_process').execFile; 
const child = execFile('node', ['--version'], (error, stdout, stderr) => { 
 if (error) { 
  throw error; 
 } 
 console.log(stdout); 
});
登入後複製

因为不会产生shell,一些I/O redirection和file globbing这些行为不支持

child_process.fork(modulePath[, args][, options])

其中modulePath表示要在子线程中执行的模块。其中options中的参数silent如果设置为true,那么子进程的stdin, stdout, stderr将会被传递给父进程,如果设置为false那么就会从父进程继承。execArgv默认的值为process.execArgv,execPath表示用于创建子进程的可执行文件。这个fork方法是child_process.spawn的一种特殊用法,用于产生一个Node.js的子进程,和spawn一样返回一个ChildProcess对象。返回的ChildProcess会有一个内置的传输通道用于在子进程和父进程之间传输数据(用ChildProcess的send方法完成)。我们必须注意,产生的Node.js进程和父进程之间是独立的,除了他们之间的IPC传输通道以外。每一个进程有独立的内存,有自己独立的V8引擎。由于产生一个子进程需要其他额外的资源分配,因此产生大量的子进程不被提倡。默认情况下,child_process.fork会使用父进程的process.execPath来产生一个Node.js实例,options中的execPath允许指定一个新的路径。通过指定execPath产生的新的进程和父进程之间通过文件描述符(子进程的环境变量NODE_CHANNEL_FD)来通信。这个文件描述符上的input/output应该是一个JSON对象。和POSIX系统调用fork不一样的是,child_process.fork不会克隆当前的进程

最后,我们来看看子进程和父进程之间是如何通信的:

服务器端的代码:

var http = require('http'); 
var cp = require('child_process'); 
var server = http.createServer(function(req, res) { 
  var child = cp.fork(dirname + '/cal.js'); 
  //每个请求都单独生成一个新的子进程 
  child.on('message', function(m) { 
    res.end(m.result + '\n'); 
  }); 
  //为其指定message事件 
  var input = parseInt(req.url.substring(1)); 
  //和postMessage很类似,不过这里是通过send方法而不是postMessage方法来完成的 
  child.send({input : input}); 
}); 
server.listen(8000);
登入後複製

子进程的代码:

function fib(n) { 
  if (n < 2) { 
    return 1; 
  } else { 
    return fib(n - 2) + fib(n - 1); 
  } 
} 
//接受到send传递过来的参数 
process.on(&#39;message&#39;, function(m) { 
  //console.log(m); 
  //打印{ input: 9 } 
  process.send({result: fib(m.input)}); 
});
登入後複製

child_process.spawn(command[, args][, options])

其中options对象的stdio参数表示子进程的stdio配置;detached表示让子进程在父进程下独立运行,这个行为与平台有关;shell如果设置为true那么就会在shell中执行命令。这个方法通过指定的command来产生一个新的进程,如果第二个参数没有指定args那么默认就是一个空的数组,第三个参数默认是如下对象,这个参数也可以用于指定额外的参数:

{
 cwd: undefined, //产生这个进程的工作目录,默认继承当前的工作目录
 env: process.env//这个参数用于指定对于新的进程可见的环境变量,默认是process.env
}
登入後複製

其中cwd用于指定子进程产生的工作目录,如果没有指定表示的就是当前工作目录。env用于指定新进程的环境变量,默认为process.env。下面的例子展示了使用ls -lh/usr来获取stdout,stderr以及exit code:

const spawn = require(&#39;child_process&#39;).spawn; 
const ls = spawn(&#39;ls&#39;, [&#39;-lh&#39;, &#39;/usr&#39;]); 
ls.stdout.on(&#39;data&#39;, (data) => { 
 console.log(`stdout: ${data}`); 
}); 
ls.stderr.on(&#39;data&#39;, (data) => { 
 console.log(`stderr: ${data}`); 
}); 
ls.on(&#39;close&#39;, (code) => { 
 console.log(`child process exited with code $[code]`); 
});
登入後複製
登入後複製

下面是一个很详细的运行"ps ax|grep ssh"的例子:

const spawn = require(&#39;child_process&#39;).spawn; 
const ps = spawn(&#39;ps&#39;, [&#39;ax&#39;]); 
const grep = spawn(&#39;grep&#39;, [&#39;ssh&#39;]); 
ps.stdout.on(&#39;data&#39;, (data) => { 
 grep.stdin.write(data); 
}); 
ps.stderr.on(&#39;data&#39;, (data) => { 
 console.log(`ps stderr: ${data}`); 
}); 
ps.on(&#39;close&#39;, (code) => { 
 if (code !== 0) { 
  console.log(`ps process exited with code $[code]`); 
 } 
 grep.stdin.end(); 
}); 
grep.stdout.on(&#39;data&#39;, (data) => { 
 console.log(`${data}`); 
}); 
grep.stderr.on(&#39;data&#39;, (data) => { 
 console.log(`grep stderr: ${data}`); 
}); 
grep.on(&#39;close&#39;, (code) => { 
 if (code !== 0) { 
  console.log(`grep process exited with code $[code]`); 
 } 
});
登入後複製

用下面的例子来检查错误的执行程序:

const spawn = require(&#39;child_process&#39;).spawn; 
const child = spawn(&#39;bad_command&#39;); 
child.on(&#39;error&#39;, (err) => { 
 console.log(&#39;Failed to start child process.&#39;); 
});
登入後複製

options.detached:

在windows上,把这个参数设置为true的话,这时候如果父进程退出了那么子进程还会继续运行,而且子进程有自己的console window。如果把子进程设置了这个为true,那么就不能设置为false了。在非window平台上,如果把这个设置为true,子进程就会成为进程组合和session的leader,这时候子进程在父进程退出以后会继续执行,不管子进程是否detached。可以参见setsid(2)。

默认情况下,父进程会等待detached子进程,然后退出。要阻止父进程等待一个指定的子进程可以使用child.unref方法,这个方法会让父进程的事件循环不包括子进程,这时候允许父进程独立退出,除非在父进程和子进程之间有一个IPC通道。下面是一个detach长期运行的进程然后把它的输出导向到一个文件:

const fs = require(&#39;fs&#39;); 
const spawn = require(&#39;child_process&#39;).spawn; 
const out = fs.openSync(&#39;./out.log&#39;, &#39;a&#39;); 
const err = fs.openSync(&#39;./out.log&#39;, &#39;a&#39;); 
const child = spawn(&#39;prg&#39;, [], { 
 detached: true,//依赖于父进程 
 stdio: [ &#39;ignore&#39;, out, err ] 
}); 
child.unref();//允许父进程单独退出,不用等待子进程
登入後複製

当使用了detached选项去产生一个长期执行的进程,这时候如果父进程退出了那么子进程就不会继续执行了,除非指定了一个stdio配置(不和父进程之间有联系)。如果父进程的stdio是继承的,那么子进程依然会和控制终端之间保持关系。

options.stdio

这个选项用于配置父进程和子进程之间的管道。默认情况下,子进程的stdin,stdout,stderr导向了ChildProcess这个对象的child.stdin,child.stdout,child.stderr流,这和设置stdio为['pipe','pipe','pipe']是一样的。stdio可以是下面的任何一个字符串

'pipe':相当于['pipe','pipe','pipe'],为默认选项

'ignore':相当于['ignore','ignore','ignore']

'inherit':相当于[process.stdin,process.stdout,process.stderr]或者[0,1,2]

一般情况下,stdio是一个数组,每一个选项对应于子进程的fd。其中0,1,2分别对应于stdin,stdout,stderr。如果还设置了多于的fds那么就会用于创建父进程和子进程之间的额外的管道,可以是下面的任何一个值:

'pipe':为子进程和父进程之间创建一个管道。父进程管道的末端会作为child_process对象的ChildProcess.stdio[fd]而存在。fds0-2创建的管道在ChildProcess.stdin,ChildProcess.stdout,ChildProcess.stderr也是存在的

'ipc':用于创建IPC通道用于在父进程和子进程之间传输消息或者文件描述符。ChildProcess对象最多有一个IPC stdio文件描述符,使用这个配置可以启用ChildProcess的send方法,如果父进程在文件描述符里面写入了JSON对象,那么ChildProcess.on("message")事件就会在父进程上触发。如果子进程是Node.js进程,那么ipc配置就会启用子进程的process.send(), process.disconnect(), process.on('disconnect'), and process.on('message')方法。

'ignore':让Node.js子进程忽视文件描述符。因为Node.js总是会为子进程开启fds0-2,设置为ignore就会导致Node.js去开启/dev/null,同时把这个值设置到子进程的fd上面。

'strem':和子进程之间共享一个可读或者可写流,比如file,socket,pipe。这个stream的文件描述符和子进程的文件描述符fd是重复的。注意:流必须有自己的文件描述符

正整数:表示父进程的打开的文件描述符。和stream对象可以共享一样,这个文件描述符在父子进程之间也是共享的
null/undefined:使用默认值。stdio的fds0,1,2管道被创建(stdin,stdout,stderr)。对于fd3或者fdn,默认为'ignore'

const spawn = require(&#39;child_process&#39;).spawn; 
// Child will use parent&#39;s stdios 
//使用父进程的stdios 
spawn(&#39;prg&#39;, [], { stdio: &#39;inherit&#39; }); 
//产生一个共享process.stderr的子进程 
// Spawn child sharing only stderr 
spawn(&#39;prg&#39;, [], { stdio: [&#39;pipe&#39;, &#39;pipe&#39;, process.stderr] }); 
// Open an extra fd=4, to interact with programs presenting a 
// startd-style interface. 
spawn(&#39;prg&#39;, [], { stdio: [&#39;pipe&#39;, null, null, null, &#39;pipe&#39;] });
登入後複製

注意:当子进程和父进程之间建立了IPC通道,同时子进程为Node.js进程,这时候开启的具有IPC通道的子进程(使用unref)直到子进程注册了一个disconnect的事件处理句柄process.on('disconnect'),这样就会允许子进程正常退出而不会由于IPC通道的打开而持续运行。

Class: ChildProcess

这个类的实例是一个EventEmitters,用于代表产生的子进程。这个类的实例不能直接创建,必须使用 child_process.spawn(), child_process.exec(), child_process.execFile(), or child_process.fork()来完成

'close'事件:

其中code表示子进程退出的时候的退出码;signal表示终止子进程发出的信号;这个事件当子进程的stdio stream被关闭的时候触发,和exit事件的区别是多个进程可能共享同一个stdio streams!(所以一个进程退出了也就是exit被触发了,这时候close可能不会触发)

'exit'事件:

其中code表示子进程退出的时候的退出码;signal表示终止子进程发出的信号。这个事件当子进程结束的时候触发,如果进程退出了那么code表示进程退出的exit code,否则没有退出就是null。如果进程是由于收到一个信号而终止的,那么signal就是这个信号,是一个string,默认为null。

注意:如果exit事件被触发了,子进程的stdio stream可能还是打开的;Node.js为SUGUBT,SIGTERM创建信号处理器,而且Node.js进程在收到信号的时候不会马上停止。Node.js会进行一系列的清理工作,然后才re-raise handled signal。见waitpid(2)

'disconnect'事件:

在子进程或者父进程中调用ChildProcess.disconnect()方法的时候会触发。这时候就不能再发送和接受信息了,这是ChildProcess.connected就是false了

'error'事件:

当进程无法产生的时候,进程无法杀死的时候,为子进程发送消息失败的时候就会触发。注意:当产生错误的时候exit事件可能会也可能不会触发。如果你同时监听了exit和error事件,那么就要注意是否会无意中多次调用事件处理函数

'message'事件:

message参数表示一个解析后的JSON对象或者初始值;sendHandle可以是一个net.Socket或者net.Server对象或者undefined。当子进程调用process.send时候触发

child.connected:

调用了disconnect方法后就会是false。表示是否可以在父进程和子进程之间发送和接受数据,当值为false就不能发送数据了
child.disconnect()

关闭子进程和父进程之间的IPC通道,这时候子进程可以正常退出如果没有其他的连接使得他保持活动。这时候父进程的child.connected和子进程的process.connected就会设置为false,这时候不能传输数据了。disconnect事件当进程没有消息接收到的时候被触发,当调用child.disconnect时候会立即触发。注意:当子进程为Node.js实例的时候如child_process.fork,这时候process.disconnect方法就会在子进程中调用然后关闭IPC通道。

child.kill([signal])

为子进程传入消息,如果没有指定参数那么就会发送SIGTERM信号,可以参见signal(7)来查看一系列信号

const spawn = require(&#39;child_process&#39;).spawn; 
const grep = spawn(&#39;grep&#39;, [&#39;ssh&#39;]); 
grep.on(&#39;close&#39;, (code, signal) => { 
 console.log( 
  `child process terminated due to receipt of signal ${signal}`); 
}); 
// Send SIGHUP to process 
grep.kill(&#39;SIGHUP&#39;);
登入後複製

ChildProcess对象在无法传输信号的时候会触发error事件。为一个已经退出的子进程发送信号虽然无法报错但是可能导致无法预料的结果。特别的,如果这个PID已经被分配给另外一个进程那么这时候也会导致无法预料的结果。

child.pid:

返回进程的PID值

const spawn = require(&#39;child_process&#39;).spawn; 
const grep = spawn(&#39;grep&#39;, [&#39;ssh&#39;]); 
console.log(`Spawned child pid: ${grep.pid}`); 
grep.stdin.end();//通过grep.stdin.end结束
登入後複製

child.send(message[, sendHandle][, callback])

当父子进程之间有了IPC通道,child.send就会为子进程发送消息,当子进程为Node.js实例,那么可以用process.on('message')事件接收

父进程为:

const cp = require(&#39;child_process&#39;); 
const n = cp.fork(`${dirname}/sub.js`); 
n.on(&#39;message&#39;, (m) => { 
 console.log(&#39;PARENT got message:&#39;, m); 
}); 
n.send({ hello: &#39;world&#39; });
登入後複製

子进程为:

process.on(&#39;message&#39;, (m) => { 
 console.log(&#39;CHILD got message:&#39;, m); 
}); 
process.send({ foo: &#39;bar&#39; });
登入後複製

子进程使用process.send方法为父进程发送消息。有一个特例,发送{cmd: 'NODE_foo'}。当一个消息在他的cmd属性中包含一个NODE_前缀会被看做使用Node.js核心(被Node.js保留)。这时候不会触发子进程的process.on('message')。而是使用process.on('internalMessage')事件,同时会被Node.js内部消费,一般不要使用这个方法。sendHandle这个用于给子进程传入一个TCP Server或者一个socket,为process.on('message')回调的第二个参数接受。callback当消息已经发送,但是子进程还没有接收到的时候触发,这个函数只有一个参数成功为null否则为Error对象。如果没有指定callback同时消息也不能发送ChildProcess就会触发error事件。当子进程已经退出就会出现这个情况。child.send返回false如果父子进程通道已经关闭,或者积压的没有传输的数据超过一定的限度,否则这个方法返回true。这个callback方法可以用于实现流控制:

下面是发送一个Server的例子:

const child = require(&#39;child_process&#39;).fork(&#39;child.js&#39;); 
// Open up the server object and send the handle. 
const server = require(&#39;net&#39;).createServer(); 
server.on(&#39;connection&#39;, (socket) => { 
 socket.end(&#39;handled by parent&#39;); 
}); 
server.listen(1337, () => { 
 child.send(&#39;server&#39;, server); 
});
登入後複製

子进程接受这个消息:

process.on(&#39;message&#39;, (m, server) => { 
 if (m === &#39;server&#39;) { 
  server.on(&#39;connection&#39;, (socket) => { 
   socket.end(&#39;handled by child&#39;); 
  }); 
 } 
});
登入後複製

这时候server就被子进程和父进程共享了,一些连接可以被父进程处理,一些被子进程处理。上面的例子如果使用dgram那么就应该监听message事件而不是connection,使用server.bind而不是server.listen,但是当前只在UNIX平台上可行。
下面的例子展示发送一个socket对象(产生两个子进程,处理normal和special优先级):

父进程为:

const normal = require(&#39;child_process&#39;).fork(&#39;child.js&#39;, [&#39;normal&#39;]); 
const special = require(&#39;child_process&#39;).fork(&#39;child.js&#39;, [&#39;special&#39;]); 
// Open up the server and send sockets to child 
const server = require(&#39;net&#39;).createServer(); 
server.on(&#39;connection&#39;, (socket) => { 
 // If this is special priority 
 if (socket.remoteAddress === &#39;74.125.127.100&#39;) { 
  special.send(&#39;socket&#39;, socket); 
  return; 
 } 
 // This is normal priority 
 normal.send(&#39;socket&#39;, socket); 
}); 
server.listen(1337);
登入後複製

子进程为:

process.on(&#39;message&#39;, (m, socket) => { 
 if (m === &#39;socket&#39;) { 
  socket.end(`Request handled with ${process.argv[2]} priority`); 
 } 
});
登入後複製

当socket被发送到子进程的时候那么父进程已经无法追踪这个socket什么时候被销毁的。这时候.connections属性就会成为null,因此我们建议不要使用.maxConnections。注意:这个方法在内部JSON.stringify去序列化消息

child.stderr:

一个流对象,是一个可读流表示子进程的stderr。他是child.stdio[2]的别名,两者表示同样的值。如果子进程是通过stdio[2]产生的,设置的不是pipe那么值就是undefined。

child.stdin:

一个可写的流对象。注意:如果子进程等待读取输入,那么子进程会一直等到流调用了end方法来关闭的时候才会继续读取。如果子进程通过stdio[0]产生,同时不是设置的pipe那么值就是undefined。child.stdin是child.stdio[0]的别名,表示同样的值。

const spawn = require(&#39;child_process&#39;).spawn;  
const grep = spawn(&#39;grep&#39;, [&#39;ssh&#39;]);  
console.log(`Spawned child pid: ${grep.pid}`);  
grep.stdin.end();//通过grep.stdin.end结束
登入後複製

child.stdio:

一个子进程管道的稀疏数组,是 child_process.spawn()函数的stdio选项,同时这个值被设置为pipe。child.stdio[0], child.stdio[1], 和 child.stdio[2]也可以通过child.stdin, child.stdout, 和 child.stderr访问。下面的例子中只有子进程的fd1(也就是stdout)被设置为管道,因此只有父进程的child.stdio[1]是一个流,其他的数组中对象都是null:

const assert = require(&#39;assert&#39;); 
const fs = require(&#39;fs&#39;); 
const child_process = require(&#39;child_process&#39;); 
const child = child_process.spawn(&#39;ls&#39;, { 
  stdio: [ 
   0, // Use parents stdin for child 
   &#39;pipe&#39;, // Pipe child&#39;s stdout to parent 
   fs.openSync(&#39;err.out&#39;, &#39;w&#39;) // Direct child&#39;s stderr to a file 
  ] 
}); 
assert.equal(child.stdio[0], null); 
assert.equal(child.stdio[0], child.stdin); 
assert(child.stdout); 
assert.equal(child.stdio[1], child.stdout); 
assert.equal(child.stdio[2], null); 
assert.equal(child.stdio[2], child.stderr);
登入後複製

child.stdout:

一个可读流,代表子进程的stdout。如果子进程产生的时候吧stdio[1]设置为除了pipe以外的任何数,那么值就是undefined。其值和child.stdio[1]一样

以上是詳解從Node.js的child_process模組來學習父子進程之間的通訊的範例程式碼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1664
14
CakePHP 教程
1423
52
Laravel 教程
1321
25
PHP教程
1269
29
C# 教程
1249
24
圖文詳解Node V8引擎的記憶體和GC 圖文詳解Node V8引擎的記憶體和GC Mar 29, 2023 pm 06:02 PM

這篇文章帶大家深入了解NodeJS V8引擎的記憶體和垃圾回收器(GC),希望對大家有幫助!

一文聊聊Node中的記憶體控制 一文聊聊Node中的記憶體控制 Apr 26, 2023 pm 05:37 PM

基於無阻塞、事件驅動建立的Node服務,具有記憶體消耗低的優點,非常適合處理海量的網路請求。在海量請求的前提下,就需要考慮「記憶體控制」的相關問題了。 1. V8的垃圾回收機制與記憶體限制 Js由垃圾回收機

聊聊如何選擇一個最好的Node.js Docker映像? 聊聊如何選擇一個最好的Node.js Docker映像? Dec 13, 2022 pm 08:00 PM

選擇一個Node的Docker映像看起來像是小事,但是映像的大小和潛在漏洞可能會對你的CI/CD流程和安全造成重大的影響。那我們要如何選擇一個最好Node.js Docker映像呢?

Node.js 19正式發布,聊聊它的 6 大功能! Node.js 19正式發布,聊聊它的 6 大功能! Nov 16, 2022 pm 08:34 PM

Node 19已正式發布,以下這篇文章就來帶大家詳解了解Node.js 19的 6 大特性,希望對大家有幫助!

一起聊聊Node中的事件循環 一起聊聊Node中的事件循環 Apr 11, 2023 pm 07:08 PM

事件循環是 Node.js 的基本組成部分,透過確保主執行緒不被阻塞來實現非同步編程,了解事件循環對建立高效應用程式至關重要。以下這篇文章就來帶大家深入了解Node中的事件循環 ,希望對大家有幫助!

深入聊聊Node中的File模組 深入聊聊Node中的File模組 Apr 24, 2023 pm 05:49 PM

文件模組是對底層文件操作的封裝,例如文件讀寫/打開關閉/刪除添加等等文件模組最大的特點就是所有的方法都提供的**同步**和**異步**兩個版本,具有sync 字尾的方法都是同步方法,沒有的都是異

聊聊用pkg將Node.js專案打包為執行檔的方法 聊聊用pkg將Node.js專案打包為執行檔的方法 Dec 02, 2022 pm 09:06 PM

如何用pkg打包nodejs可執行檔?以下這篇文章跟大家介紹一下使用pkg將Node專案打包為執行檔的方法,希望對大家有幫助!

node無法用npm指令怎麼辦 node無法用npm指令怎麼辦 Feb 08, 2023 am 10:09 AM

node無法用npm指令是因為沒有正確配置環境變量,其解決方法是:1、開啟“系統屬性”;2、找到“環境變數”->“系統變數”,然後編輯環境變數;3、找到nodejs所在的資料夾;4、點選「確定」即可。

See all articles