Node.js:深入承诺
#javascript #node #promise #javascriptprmise

我们所有人都知道承诺。它们是对Node.js的低级构建块的改进,并且被程序员广泛使用。作为程序员,我们应该考虑代码的可读性。这是承诺的最重要特征。他们使代码更可读。

在本文中,我们将进一步了解Promise Library及其优势的功能。让我们从回调开始 -

回调:
我们已经看到了许多回调的定义,例如回调是传递给另一个函数的函数。在node.js中,回调的定义基于其异步性。

通知完成异步功能的最基本机制称为回调。

有某些缺点,例如 -

  • 回调地狱
  • 金字塔问题
  • 关闭和重命名的参数
  • 错误处理

让我们先查看回调地狱问题。有时,我们希望在完成另一个任务后执行代码。在编程中,这称为任务的顺序执行(异步)。

在此阶段,我认为我们熟悉回调函数的基本结构。让我们检查以下示例 -

async1((err,data) =>{
    async2((err,data)=> {
      async3((err,data)=> {  
    //...     })  
 }) 
})

在这里,我们将一个函数的执行结果传递给另一个函数,例如任务的顺序执行。这将我们的代码带入了一个不可读取和无法控制的斑点,称为“回调地狱”。您可以看到以这种方式编写的代码如何假定由于深嵌套而导致金字塔的形状,这就是为什么它也被俗称为“厄运的金字塔”。

另一个非常重要的部分是检查我们是否在任何结果中都有错误。它需要在应用程序中进一步通过。串行执行流程似乎不必要地复杂且容易出错。如果我们忘记转发错误,那么它就会丢失,如果我们忘记抓住某些同步代码抛出的任何例外,那么程序就会崩溃。这称为回调的主要错误处理问题。

承诺:
如您所见,这里最基本的问题是代码的可读性。现在解决这个问题,JavaScript开发人员提出了一个库,他们称之为Promise A+。

承诺是Ecmascript 2015标准的一部分(或ES6,这就是为什么它们也称为ES6承诺),并且自版本第4版以来在Node.js中本地可用。当周围有数十个实现时,最初具有不同的特征和行为。最终,大多数实施方式都以称为Promises/a+的标准解决。

简单地说,我们可以说 - 迈向更好的异步代码体验的第一步是承诺,一个对象具有异步操作的状态和最终结果。<<<<<<<<<<< /p>

我们将从此处详细介绍有关承诺的更多详细信息 -

要了解承诺如何改变我们的代码,让我们考虑以下基于回调的代码:

asyncOperation(arg, (err, result) => {
   if(err) 
    {     
      // handle the error   
    } 
  // do stuff with the result 
})

承诺使我们能够将这种典型的延续风格代码转换为一个更好的结构化和更优雅的代码,例如以下内容:

asyncOperationPromise(arg)   
.then(result => {     
   // do stuff with result 
 },
 err => {    
   // handle the error  
 })

在上面的代码中,asyncoperationpromise()是返回promise,然后我们可以使用它来接收函数最终结果的履行值或拒绝原因。承诺最无能的部分是,我们可以将一个操作的结果传递给另一个操作 -


asyncOperationPromise(arg)  
 .then(result1 => {
     // returns another promise
    return asyncOperationPromise(arg2) 
  })
   .then(result2 => {
     // returns a value   
    return 'done'   
   })
   .then(undefined, err => { 
    // any error in the chain is caught here 
  })

与嵌套回调相比,我们可以看到上面的代码更可读。我们也在这里执行同一任务的顺序执行。这是在node.js中写下承诺的最简单形式,但是要做得更好,javaScript提供了一个本机解决方案,他们称之为Promise API。

承诺API:

new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(new Date())
    }, milliseconds)
  })

这只是一个概述,可以让您了解我们可以通过承诺做什么。

Promise构造函数(新的Promise((RESOLVE,recions)=>))创建了一个新的承诺实例,该实例根据作为参数提供的函数的行为来实现或拒绝。提供给构造函数的功能将收到两个参数:

resolve(obj):这是一个函数,当调用时,将以所提供的满足价值实现承诺,如果OBJ为一个值,则将是OBJ。如果OBJ是诺言或当时的承诺,这将是OBJ的实现价值。
拒绝(err):这拒绝了理由错误的承诺。这是ERR是错误的实例。
建立诺言:
现在,让我们看看我们如何使用其构造函数来创造诺言。从头开始创建诺言是一个低级操作,通常需要转换使用另一种异步样式的API(例如基于回调的样式)时。在大多数情况下,我们作为开发人员是其他图书馆产生的承诺的消费者,而我们创造的大多数承诺都来自当时的()方法。尽管如此,在某些高级方案中,我们需要使用其构造函数手动创建诺言。

要演示如何使用承诺构造函数,让我们创建一个函数,该函数返回一个在指定数量的毫秒数之后以当前日期满足的承诺。让我们看一下:

function delay (milliseconds) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(new Date())
    }, milliseconds)
  })
}

您可能已经猜到了,我们使用settimeout调用了Promise构造函数的分解功能。我们可以注意到函数的整个主体是如何由承诺构造函数包裹的;这是从头开始创建承诺时会看到的常见代码模式。

我们刚刚创建的delay()函数可以与以下一些代码一起使用:

console.log(`Delaying...${new Date().getSeconds()}s`)
delay(1000)
  .then(newDate => {
    console.log(`Done ${newDate.getSeconds()}s`)
  })

如果代码或系统丢弃了任何错误,我们需要捕获它们,但是它比我们在回调模式中所做的要简单得多。

现在是最好的部分。如果抛出异常(使用抛出语句),则THE()方法返回的承诺将自动拒绝,而将其作为拒绝原因提供的例外。这是我们之前看到的回调错误处理的巨大优势,因为这意味着有希望,异常将自动在整个链条上传播。

async/等待的承诺:

承诺是解决诸如回调地狱和厄运金字塔等问题的最佳方法,但是在编写顺序异步代码时,它们仍然是次优的解决方案。然后我们需要调用()并为链中的每个任务创建一个新功能。对于绝对是日常编程中最常用的控制流来说,这仍然太多了。 JavaScript需要一种适当的方法来处理无处不在的异步顺序执行流,答案是在异步函数的Ecmascript标准中以介绍和等待表达式的介绍而到达的(Shorts/for Short)

异步/等待二分法使我们能够写出在每个异步操作中似乎阻塞的功能,等待结果,然后再继续进行以下陈述。正如我们将看到的,使用异步/等待的任何异步代码具有与传统同步代码相当的可读性。

今天,异步/等待是在Node.js和JavaScript中处理异步代码的推荐结构。但是,异步/等待并不能取代我们到目前为止学到的有关异步控制流模式的所有知识。相反,正如我们将看到的那样,异步/等待着背式背pones

现在让我们以异步/等待 -
为例

function delay (milliseconds) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(new Date())
    }, milliseconds)
  })
} 
async function playingWithDelays () { 
  console.log('Delaying...', new Date())  
  const dateAfterOneSecond = await delay(1000)
  console.log(dateAfterOneSecond)  
  const dateAfterThreeSeconds = await delay(3000)
  console.log(dateAfterThreeSeconds)   return 'done' 
}

从上一个功能中可以看出,异步/等待似乎像魔术一样起作用。该代码甚至看起来都没有任何异步操作。但是,不要误会;此函数不会同步运行(由于某种原因,它们称为异步函数!)。在每个等待的表达式上,暂停该功能的执行,保存其状态,并将控制返回到事件循环。一旦等待解决的诺言,控制权就会归还给异步功能,返回承诺的履行价值。

与异步/等待的错误处理:
异步/等待的目的不是在标准条件下提高异步代码的可读性,但在处理错误时也有所帮助。实际上,异步/等待的最大收益之一是能够使尝试/捕获块的行为正常化,并使其与同步投掷和异步的承诺拒绝无缝地工作。让我们以一个例子来证明这一点。

统一的尝试 - 捕获体验
让我们定义一个函数,该函数返回承诺,该函数在给定数量的毫秒数之后以错误拒绝。这与我们已经非常了解的delay()函数非常相似:

function delayError (milliseconds) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(new Error(`Error after ${milliseconds}ms`))
    }, milliseconds)
  })
}

接下来,让我们实现一个异步函数,该功能可以同步丢弃错误或等待拒绝的承诺。此功能说明了同步投掷和承诺拒绝如何被同一捕获块捕获:


async function playingWithErrors (throwSyncError) {
  try {
    if (throwSyncError) {
      throw new Error('This is a synchronous error')
    }
    await delayError(1000)
  } catch (err) {
    console.error(`We have an error: ${err.message}`)
  } finally {
    console.log('Done')
  }
}

现在,错误处理的方式是:简单,可读,最重要的是,支持同步和异步错误。

上面,我们涵盖了与承诺相关的所有重要场景。我希望您会发现这些文章有用。给它一些鼓掌,让他人也找到它!

如果您发现有帮助,请单击下面几次的闭合按钮,以表示您对作者的支持ð