2015-12-22 111 views
3

我对Node.js和JavaScript比较陌生 - 如果下面的问题是愚蠢的,请尽量使用它。 对我来说,异步处理的承诺是有道理的,但在串行/顺序处理方面,我并不是100%确信使用promise。让我们看一个例子(伪代码):使用承诺进行顺序处理

目标:读取文件,处理从文件中读取的内容并使用HTTP发送呼叫发送通知 。

bendUniverseWithoutPromise: function() { 

    var data = fs.readFileSync(..); //Read the file 
    var result = processData(data); 
    this.postNotification(data); 

} 

在上面的函数中,processData()不能运行,直到我们读取文件。在我们完成处理之前,我们无法发送通知。

让我们看看一个稍微不同的版本(假设上述各方法调用的返回一个承诺或我们总结他们的承诺):

bendUniverseWithPromise: function() { 
     return new Promise(function() { 
     fs.readFileAsync(fileName) 
      .then(processData(data)) 
      .then(postNotification(result)) 
     })   
    } 

现在,我的问题是:

  1. 看到在这种情况下我们需要串行/顺序处理,承诺版本如何比非承诺版本更好?有什么比第一个例子更好?也许这是一个不好的例子,但那么什么是证明差异的好例子?
  2. 除了语法,承诺版本的代码可读性方面增添了些许(只有一点点),并可以得到嵌套的承诺,上下文(这个!)等
  3. 我明白,在技术上,第一相当复杂方法将不会返回,直到完成所有处理并且第二个将立即返回并且处理虽然仍然是连续的(在该方法的上下文中)将在后台继续。
  4. 是否有关于使用承诺的一般规则?有没有任何模式和反模式?

在此先感谢您。

+0

一个很好的规则是,也许它需要时间和用户会认为我的应用程序没有响应,或者在执行此操作的用户可以做其他事情?如果是这样,去异步 – Luizgrs

+0

你是不是指'this.postNotification(result);'? – Bergi

+0

您可能会发现[这些经验法则](http://stackoverflow.com/a/25756564/1048572)娱乐 – Bergi

回答

1

首先,让我们纠正异步代码:现在

bendUniverseWithPromise: function() { 
    return fs.readFileAsync(fileName) 
      .then(processData) 
      .then(postNotification); 
} 

,上面是(几乎是,如果它完成)反模式 - 在explicit construction anti-pattern

至于为什么你要使用的承诺版本,那么,它是异步的 。它允许在异步(主要是I/O)操作,等待其他操作发生。

注意:fs.readFileAsync默认情况下不返回承诺,需要“promisified”。

+0

我不会称这是明确的施工反模式,只是它不起作用。根本没有任何“决心”电话 – Bergi

+0

@Bergi - 是的,你是对的。甚至没有注意到它不是真正可用的代码。 – Amit

+0

...并且它仍然不是可用的代码,请检查@ dape的答案,以纠正错误代码 – Bergi

2

我会尽量通过进一步考虑你的例子来回答你的四点。

可以说第一个操作(文件读取)是一个缓慢的I/O绑定操作,需要900 ms。处理和通知分别为CPU绑定和I/O绑定,每个都需要50 ms。 What do the terms “CPU bound” and “I/O bound” mean?

现在,两个版本都将花费相同的1000毫秒来完成,但第二个示例更好地利用可用资源,因为它是异步的。这就是基于承诺的版本的优点。第一个版本将使服务器在整整一秒内完全无响应,而第二个版本只会在50 ms CPU绑定处理步骤期间使服务器无响应。

当我们考虑这些请求中的10个同时进入时,希望这变得更加清晰。第一个例子一次一个地处理它们,在1秒后服务请求#1,在2秒后服务#2,等等,在10秒后结束。它的平均表现是1 req/s。第二个版本将为请求#1启动一个文件读取,然后立即继续请求#2,启动另一个文件读取,等等为所有请求。所有请求都会在1秒左右完成读取操作,假设开销为100毫秒,磁盘读取带宽很少或没有饱和。然后处理将排队,所有请求总共花费500毫秒。最后,我们可以并行执行通知发布,因为它再次受I/O限制。然后,在这个理想化的例子中,所有的请求都将在大约1.5秒内完成,超过6次/秒,性能提高6倍。这完全是由于异步性提供了更好的机智。

因此规则是,总是在执行I/O绑定工作时使用异步/承诺。


旁注:

你的第二个例子是不正确的,因为在该范围中没有定义dataresult可变,正确的版本将只功能传递到then()

bendUniverseWithPromise: function (fileName) { 
    return fs.readFileAsync(fileName) 
      .then(processData) 
      .then(postNotification)   
} 
+1

我想你需要通过'this.postNotification.bind(this)',但是为了匹配同步代码 – Bergi