如果下面的问题是愚蠢的话,我对Node.js和JavaScript相对较新 - 请原谅。 对我来说,异步处理的承诺是有道理的,但在串行/顺序处理方面,我并不是100%肯定使用promises。让我们看一个例子(伪代码):
目标:读取文件,处理从文件中读取的内容并发送通知 使用HTTP post post。
bendUniverseWithoutPromise: function() {
var data = fs.readFileSync(..); //Read the file
var result = processData(data);
this.postNotification(data);
}
在上面的函数中,在我们读取文件之前,processData()无法运行。在我们完成处理之前,我们无法发送通知。
让我们看一个稍微不同的版本(假设上面的每个方法调用都返回一个promise或者我们将它们包装在一个promise中):
bendUniverseWithPromise: function() {
return new Promise(function() {
fs.readFileAsync(fileName)
.then(processData(data))
.then(postNotification(result))
})
}
现在,我的问题是:
提前谢谢。
答案 0 :(得分:2)
我将通过进一步举例来尝试回答你的所有四点。
让我们说第一个操作(文件读取)是一个缓慢的I / O绑定操作,需要900毫秒。处理和通知分别受CPU限制和I / O限制,每个采用50 ms。 What do the terms “CPU bound” and “I/O bound” mean?
现在,两个版本都将花费相同的1000毫秒来完成,但第二个示例更好地利用了可用资源,因为它是异步的。这是基于承诺的版本的优点。第一个版本将使服务器完全没有响应一整秒,而第二个版本只会使服务器在50 ms CPU绑定处理步骤期间无响应。
当我们考虑其中10个请求同时进入时,这有望变得更加清晰。第一个例子一次一个地通过它们,在1s之后提供请求#1,在2s之后提供#2,依此类推,在10s之后完成。其平均性能为1 req / s。第二个版本将启动对请求#1的文件读取,然后立即继续请求#2,启动另一个文件读取,依此类推所有请求。然后,所有请求将在大约1秒内完成读取,假设开销为100毫秒,磁盘读取带宽很少或没有饱和。然后处理将排队,对所有请求总共花费500毫秒。最后,我们可以并行进行通知发布,因为它再次受I / O限制。然后,在这个理想化的示例中,所有请求将在大约1.5秒内完成,超过6 req / s,性能提高6倍。这完全是由于异步性提供了更好的资源。
因此,规则是在执行I / O绑定工作时始终使用async / promises 。
旁注:
您的第二个示例不正确,因为该范围中没有定义data
或result
变量,正确的版本只会将函数传递给then()
。
bendUniverseWithPromise: function (fileName) {
return fs.readFileAsync(fileName)
.then(processData)
.then(postNotification)
}
答案 1 :(得分:1)
首先让我们更正异步代码:
bendUniverseWithPromise: function() {
return fs.readFileAsync(fileName)
.then(processData)
.then(postNotification);
}
现在,上面的是(差不多,已经完成)反模式 - explicit construction anti-pattern。
至于为什么你想要使用承诺的版本,那么它是异步的 ..它允许在等待异步(主要是I / O)操作时进行其他操作。
注意:fs.readFileAsync
默认情况下不会返回承诺,需要“保证”。