Skip to content

承诺(Promises)

承诺

我们人类会给出或接受承诺在某个时间点做某些活动。如果我们遵守承诺,我们会让别人高兴,但如果我们不遵守承诺,可能会导致不满。JavaScript 中的 Promise 与上述示例有一些共同点。

Promise 是在 JavaScript 中处理异步操作的一种方式。它允许处理程序处理异步操作的最终成功值或失败原因。这让异步方法像同步方法一样返回值:异步方法不是立即返回最终值,而是返回一个承诺在将来某个时间点提供该值。

Promise 处于以下状态之一:

  • pending(待定):初始状态,既未完成也未拒绝。
  • fulfilled(已完成):意味着操作成功完成。
  • rejected(已拒绝):意味着操作失败。

待定的 promise 可以用值完成,或者用原因(错误)拒绝。当这些选项中的任何一个发生时,由 promise 的 then 方法排队的相关处理程序将被调用。(如果在附加相应处理程序时 promise 已经完成或拒绝,则将调用处理程序,因此异步操作完成和其处理程序附加之间没有竞争条件。)

由于 Promise.prototype.then() 和 Promise.prototype.catch() 方法返回 promises,它们可以被链式调用。

回调函数

为了很好地理解 promise,让我们首先理解回调。让我们看看以下回调。从以下代码块中,你会注意到回调和 promises 之间的区别。

  • 回调 让我们看一个可以接受两个参数的回调函数。第一个参数是 err,第二个是 result。如果 err 参数为 false,则不会有错误,否则它将返回错误。

在这种情况下,err 有一个值,它将返回 err 块。

js
//回调
const doSomething = callback => {
  setTimeout(() => {
    const skills = ['HTML', 'CSS', 'JS']
    callback('It did not go well', skills)
  }, 2000)
}

const callback = (err, result) => {
  if (err) {
    return console.log(err)
  }
  return console.log(result)
}

doSomething(callback)
sh
// 2秒后它将打印
It did not go well

在这种情况下,err 为 false,它将返回 else 块,即结果。

js
const doSomething = callback => {
  setTimeout(() => {
    const skills = ['HTML', 'CSS', 'JS']
    callback(false, skills)
  }, 2000)
}

doSomething((err, result) => {
  if (err) {
    return console.log(err)
  }
  return console.log(result)
})
sh
// 2秒后它将打印技能
["HTML", "CSS", "JS"]

Promise 构造函数

我们可以使用 Promise 构造函数创建一个 promise。我们可以使用关键字 new 后跟单词 Promise 再后跟括号来创建一个新的 promise。在括号内,它接受一个 callback 函数。promise 回调函数有两个参数,即 resolvereject 函数。

js
// 语法
const promise = new Promise((resolve, reject) => {
  resolve('success')
  reject('failure')
})
js
// Promise
const doPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    const skills = ['HTML', 'CSS', 'JS']
    if (skills.length > 0) {
      resolve(skills)
    } else {
      reject('Something wrong has happened')
    }
  }, 2000)
})

doPromise
  .then(result => {
    console.log(result)
  })
  .catch(error => console.log(error))
sh
["HTML", "CSS", "JS"]

上述 promise 已通过 resolve 解决。 让我们再看一个当 promise 通过 reject 解决的例子。

js
// Promise
const doPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    const skills = ['HTML', 'CSS', 'JS']
    if (skills.includes('Node')) {
      resolve('fullstack developer')
    } else {
      reject('Something wrong has happened')
    }
  }, 2000)
})

doPromise
  .then(result => {
    console.log(result)
  })
  .catch(error => console.error(error))
sh
Something wrong has happened

Fetch API

Fetch API 提供了一个用于获取资源(包括跨网络)的接口。对于任何使用过 XMLHttpRequest 的人来说,它都会很熟悉,但新的 API 提供了更强大和灵活的功能集。在这个挑战中,我们将使用 fetch 来请求 url 和 API。除此之外,让我们看看使用 fetch API 访问网络资源时 promises 的使用案例演示。

js
const url = 'https://restcountries.com/v2/all' // 国家 api
fetch(url)
  .then(response => response.json()) // 将 API 数据作为 JSON 访问
  .then(data => {
    // 获取数据
    console.log(data)
  })
  .catch(error => console.error(error)) // 如果出现问题则处理错误

Async 和 Await

Async 和 await 是处理 promises 的优雅方式。它易于理解且编写简洁。

js
const square = async function (n) {
  return n * n
}

square(2)
sh
Promise {<resolved>: 4}

函数前面的单词 async 意味着该函数将返回一个 promise。上面的 square 函数不是返回值而是返回 promise。

我们如何从 promise 中访问值?要从 promise 中访问值,我们将使用关键字 await

js
const square = async function (n) {
  return n * n
}
const value = await square(2)
console.log(value)
sh
4

现在,正如你从上面的例子中看到的,在函数前面写 async 创建一个 promise,要从 promise 中获取值,我们使用 await。Async 和 await 是一起的,一个不能没有另一个而存在。

让我们使用 promise 方法和 async 和 await 方法获取 API 数据。

  • promise
js
const url = 'https://restcountries.com/v2/all'
fetch(url)
  .then(response => response.json())
  .then(data => {
    console.log(data)
  })
  .catch(error => console.error(error))
  • async 和 await
js
const fetchData = async () => {
  try {
    const response = await fetch(url)
    const countries = await response.json()
    console.log(countries)
  } catch (err) {
    console.error(err)
  }
}
console.log('===== async and await')
fetchData()

🌕 你是真实的,你遵守了你的承诺,你到达了第18天。遵守你的承诺并通过 resolve 解决挑战。你在通往伟大的道路上已经前进了18步。现在为你的大脑和肌肉做一些练习。

练习

js
const countriesAPI = 'https://restcountries.com/v2/all'
const catsAPI = 'https://api.thecatapi.com/v1/breeds'

练习:第1级

  1. 使用 fetch 读取国家 API 并打印国家名称、首都、语言、人口和面积。

练习:第2级

  1. 将所有猫的名字打印到 catNames 变量中。

练习:第3级

  1. 读取猫 api 并找到猫在公制单位中的平均重量。
  2. 读取国家 api 并找出10个最大的国家
  3. 读取国家 api 并计算世界上用作官方语言的语言总数。

🎉 恭喜!🎉