好的,让我们逐个分析一下。首先要知道,Node.js 是一个单线程的进程,如果需要执行阻塞进程(例如读取文件:创建事件指针、读取文件句柄、设置文件路径、设置打开模式等),最好使用异步函数,这些函数在同一页或线程池的另一个线程上执行。
1)当需要执行独立于主程序流的操作时,使用异步函数是很好的选择。但是,在主程序非常需要异步函数的数据/响应或各种独立的异步函数相互关联时,使用异步函数并不理想。
首先,我们不会将程序文件称为“主程序”,因为在 Node.js 世界中没有子程序(我不是说模块之类的)。
现在,当您说在需要立即输出时不应使用任何异步函数时,实际上是正确的。让我们看下面的例子:
...
const data = readFile( 'fileName', ( data, output ) => {
...
} );
console.log( data );
在上述情况中,我们不会使用异步函数(在传统意义上)。然而,在ES6及以上版本中,我们可以使用可爱的
async/await
范例:
https://javascript.info/async-await。
const data = await readFile( 'filename' );
await
使调用伪同步:它的行为像一个
async
函数,但是会有一个暂停的线程等待输出。所以,在这里,你是完全正确的!让我们继续。
2)不应该依赖异步函数的输出结果在主程序流中进行操作。因为异步总是在主流程之后执行。所以,如果需要在主流程中执行某些函数,最好将其定义为同步而不是异步。
在这里,你说async
在主流程之后运行。现在,那是不正确的。让我画一个简单的线程评估和执行图:
假设有两个同步函数A()
和B()
,它们对应的线程是th__A
和th__B
,它们将会如下进行:
th__a ---> th__b
如果它们按顺序被解雇,
A()
然后是
B()
。它等待第一个同步(或阻塞)过程的评估,然后执行第二个。显然,它不是在整个执行结束后才执行。
但是,如果它们现在是异步函数,它们将并行执行。假设
A()
是同步函数,
B()
是具有与上述相同线程名称的异步函数,则执行类似于以下内容:
th__a ----
- - th__b ->
其中,-
表示一个时钟周期,->
表示执行结束。我们可以看到,首先触发了A()
,然后在新线程上触发B()
。
我想这很有道理。现在回来说,如果你需要立即使用它们并将它们作为异步调用,则需要使用await
。
3) 当独立的异步函数被调用时,一种常见方法是使用 promises 和 callbacks 来调用后续操作(异步函数)。
完全正确。
比如,我们定义了一个名为sayHello()
的函数:
const sayHello = () => {
const P = Q.defer();
return p.promise;
};
这里使用了优秀的Promise库Q
,我们可以按照以下方式进行调用:
sayHello.then( ( data ) => {
console.log( data ); // P.resolve(..) is working here since the promise was successful.
} ).catch( ( err ) => {
console.log( err ); // P.reject(..) is working here since there was a problem.
} );
或者您可以像使用fs.readFile(...)
这样的回调函数:
fs.readFile( 'fileName', ( e, data ) => {
if( e ) { return console.log( e ); }
} );
4) 在异步函数中仍然可以调用同步函数,但是如果从同步函数/操作调用异步函数,则程序可能无法按预期工作,因为异步函数将仅在最后执行?
不完全如此。请参考第(2)点。它涉及线程而不是静态进程。您可以在异步函数中很好地调用同步函数,并且它将完美地工作。
当您读取文件时,例如想要通过 \n
或换行符来拆分数据:
...
if( e ) { return console.log( e ); }
const dataLines = e.split( '\n' ); // this will work brilliantly
...
我希望这能让一切变得清晰易懂! :)