javascript_了解JavaScript承诺

javascript

承诺简介 (Introduction to promises)

A promise is commonly defined as a proxy for a value that will eventually become available.

通常将promise定义为最终将变为可用值的代理

Promises are one way to deal with asynchronous code, without writing too many callbacks in your code.

承诺是处理异步代码的一种方法,而无需在代码中编写过多的回调。

Although they’ve been around for years, they were standardized and introduced in ES2015, and now they have been superseded in ES2017 by async functions.

尽管它们已经存在多年了,但是它们已经在ES2015中进行了标准化和引入,现在,它们已经在ES2017中异步功能所取代。

Async functions use the promises API as their building block, so understanding them is fundamental even if in newer code you’ll likely use async functions instead of promises.

异步函数将promise API用作其构建块,因此即使在较新的代码中您可能会使用异步函数代替promise,对它们的理解也是基础。

简而言之,诺言如何运作 (How promises work, in brief)

Once a promise has been called, it will start in pending state. This means that the caller function continues the execution, while it waits for the promise to do its own processing, and give the caller function some feedback.

承诺被调用后,它将以待处理状态开始。 这意味着调用方函数继续执行,同时等待promise进行自己的处理,并向调用方函数提供一些反馈。

At this point, the caller function waits for it to either return the promise in a resolved state, or in a rejected state, but the function continues its execution while the promise does it work.

此时,调用方函数将等待它以已解决状态或已拒绝状态返回promise,但是当promise起作用时该函数将继续执行

哪个JS API使用承诺? (Which JS API use promises?)

In addition to your own code and library code, promises are used by standard modern Web APIs such as:

除了您自己的代码和库代码之外,标准的现代Web API还使用了promise,例如:

It’s unlikely that in modern JavaScript you’ll find yourself not using promises, so let’s start diving right into them.

在现代JavaScript中,您不太可能会发现自己没有使用Promise,因此让我们开始深入研究它们。



创造承诺 (Creating a promise)

The Promise API exposes a Promise constructor, which you initialize using new Promise():

Promise API公开了一个Promise构造函数,您可以使用new Promise()初始化:

let done = true

const isItDoneYet = new Promise((resolve, reject) => {
  if (done) {
    const workDone = 'Here is the thing I built'
    resolve(workDone)
  } else {
    const why = 'Still working on something else'
    reject(why)
  }
})

As you can see the promise checks the done global variable, and if that’s true, we return a resolved promise, otherwise a rejected promise.

如您所见,promise检查done全局变量,如果是,那么我们返回一个已解决的promise,否则返回一个被拒绝的promise。

Using resolve and reject we can communicate back a value, in the above case we just return a string, but it could be an object as well.

使用resolvereject我们可以返回一个值,在上述情况下,我们只返回一个字符串,但是它也可以是一个对象。



兑现承诺 (Consuming a promise)

In the last section, we introduced how a promise is created.

在上一节中,我们介绍了如何创建承诺。

Now let’s see how the promise can be consumed or used.

现在,让我们来看看如何承诺可以消耗或使用。

const isItDoneYet = new Promise()
//...

const checkIfItsDone = () => {
  isItDoneYet
    .then(ok => {
      console.log(ok)
    })
    .catch(err => {
      console.error(err)
    })
}

Running checkIfItsDone() will execute the isItDoneYet() promise and will wait for it to resolve, using the then callback, and if there is an error, it will handle it in the catch callback.

运行checkIfItsDone()将执行isItDoneYet() ,并使用then回调等待其解决,如果有错误,它将在catch回调中对其进行处理。



连锁承诺 (Chaining promises)

A promise can be returned to another promise, creating a chain of promises.

一个承诺可以返回到另一个承诺,从而创建一个承诺链。

A great example of chaining promises is given by the Fetch API, a layer on top of the XMLHttpRequest API, which we can use to get a resource and queue a chain of promises to execute when the resource is fetched.

链接承诺的一个很好的例子是Fetch API ,它是XMLHttpRequest API之上的一层,我们可以使用它来获取资源,并在获取资源时排队执行承诺。

The Fetch API is a promise-based mechanism, and calling fetch() is equivalent to defining our own promise using new Promise().

Fetch API是一种基于承诺的机制,调用fetch()等效于使用new Promise()定义我们自己的承诺。

链接承诺的示例 (Example of chaining promises)

const status = response => {
  if (response.status >= 200 && response.status < 300) {
    return Promise.resolve(response)
  }
  return Promise.reject(new Error(response.statusText))
}

const json = response => response.json()

fetch('/todos.json')
  .then(status)
  .then(json)
  .then(data => {
    console.log('Request succeeded with JSON response', data)
  })
  .catch(error => {
    console.log('Request failed', error)
  })

In this example, we call fetch() to get a list of TODO items from the todos.json file found in the domain root, and we create a chain of promises.

在此示例中,我们调用fetch()从域根目录中的todos.json文件中获取TODO项目列表,并创建一个Promise链。

Running fetch() returns a response, which has many properties, and within those we reference:

运行fetch()返回一个response ,它具有许多属性,在我们引用的属性内:

  • status, a numeric value representing the HTTP status code

    status ,一个表示HTTP状态代码的数值

  • statusText, a status message, which is OK if the request succeeded

    statusText ,状态消息,如果请求成功,则OK

response also has a json() method, which returns a promise that will resolve with the content of the body processed and transformed into JSON.

response还有一个json()方法,该方法返回一个promise,该promise将与处理并转换为JSON的正文内容一起解析。

So given those premises, this is what happens: the first promise in the chain is a function that we defined, called status(), that checks the response status and if it’s not a success response (between 200 and 299), it rejects the promise.

因此,考虑到这些前提,就会发生这种情况:链中的第一个promise是我们定义的函数,即status() ,它检查响应状态,如果不是成功响应(介于200和299之间),它将拒绝诺言。

This operation will cause the promise chain to skip all the chained promises listed and will skip directly to the catch() statement at the bottom, logging the Request failed text along with the error message.

此操作将导致promise链跳过列出的所有链接的promise,并将直接跳到底部的catch()语句,并记录Request failed文本和错误消息。

If that succeeds instead, it calls the json() function we defined. Since the previous promise, when successful, returned the response object, we get it as an input to the second promise.

如果成功,它将调用我们定义的json()函数。 由于上一个承诺成功后返回了response对象,因此我们将其作为第二个承诺的输入。

In this case, we return the data JSON processed, so the third promise receives the JSON directly:

在这种情况下,我们返回经过JSON处理的数据,因此第三个promise直接接收JSON:

.then((data) => {
  console.log('Request succeeded with JSON response', data)
})

and we log it to the console.

然后将其记录到控制台。



处理错误 (Handling errors)

In the above example, in the previous section, we had a catch that was appended to the chain of promises.

在上面的例子中,上一节中,我们有一个catch这是附加承诺的链条。

When anything in the chain of promises fails and raises an error or rejects the promise, the control goes to the nearest catch() statement down the chain.

当promise链中的任何内容失败并且引发错误或拒绝promise时,控件将转到链中最近的catch()语句。

new Promise((resolve, reject) => {
  throw new Error('Error')
}).catch(err => {
  console.error(err)
})

// or

new Promise((resolve, reject) => {
  reject('Error')
}).catch(err => {
  console.error(err)
})

级联错误 (Cascading errors)

If inside the catch() you raise an error, you can append a second catch() to handle it, and so on.

如果在catch()内部引发错误,则可以附加第二个catch()来处理它,依此类推。

new Promise((resolve, reject) => {
  throw new Error('Error')
})
  .catch(err => {
    throw new Error('Error')
  })
  .catch(err => {
    console.error(err)
  })


编排承诺 (Orchestrating promises)

Promise.all() (Promise.all())

If you need to synchronize different promises, Promise.all() helps you define a list of promises, and execute something when they are all resolved.

如果您需要同步不同的Promise.all()Promise.all()可帮助您定义一个Promise.all()列表,并在它们全部解决后执行一些操作。

Example:

例:

const f1 = fetch('/something.json')
const f2 = fetch('/something2.json')

Promise.all([f1, f2])
  .then(res => {
    console.log('Array of results', res)
  })
  .catch(err => {
    console.error(err)
  })

The ES2015 destructuring assignment syntax allows you to also do

ES2015解构分配语法使您还可以

Promise.all([f1, f2]).then(([res1, res2]) => {
  console.log('Results', res1, res2)
})

You are not limited to using fetch of course, any promise is good to go.

当然,您不仅限于使用fetch任何承诺都是可以的

Promise.race() (Promise.race())

Promise.race() runs as soon as one of the promises you pass to it resolves, and it runs the attached callback just once with the result of the first promise resolved.

Promise.race()在您传递给它的一个诺言解析后立即运行,并且在第一个诺言得到解决的情况下,它仅运行附加的回调一次。

Example:

例:

const promiseOne = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, 'one')
})
const promiseTwo = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'two')
})

Promise.race([promiseOne, promiseTwo]).then(result => {
  console.log(result) // 'two'
})

常见错误 (Common errors)

Uncaught TypeError:未定义不是一个承诺 (Uncaught TypeError: undefined is not a promise)

If you get the Uncaught TypeError: undefined is not a promise error in the console, make sure you use new Promise() instead of just Promise()

如果在控制台中收到Uncaught TypeError: undefined is not a promise new Promise()错误,请确保使用new Promise()而不是Promise()

翻译自: https://flaviocopes.com/javascript-promises/

javascript

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值