Promise - JavaScript 概念
这是我尝试解释33 个 JS 概念系列文章的一部分。
这部分对应于“承诺”。
背景
JavaScript 是一种单线程语言,这意味着它一次只能处理一件事。
我知道这听起来很棒,无需担心多条路径的问题。但还有一点需要注意。浏览器中始终运行着一个 UI 线程,它需要始终保持响应。如果 JavaScript 的焦点都集中在 UI 线程上,那么谁来从 API 获取数据呢?
我本想详细解释一下,但Philip Roberts 在他的 JSConf 演讲中已经做得非常出色了。
所以 JavaScript 需要异步处理一些事情,不能干扰单个线程。你想调用一个 API 吗?
- 发起 API 调用
- 让 API 调用在浏览器线程上完成。
- 让浏览器返回结果。
- 处理结果。
Promise 是实现步骤 4 的一种(简单)方法,即编写返回到某一行并处理给定语句结果的代码。
什么是承诺?
Promise 本质上是一个特殊对象(就像函数也是对象一样),它有一个then方法,当异步操作完成时,该方法会被调用。
虽然我们可以自定义 Promise,但大多数情况下,我们处理的是内置函数或第三方库返回的 Promise。首先,让我们看看它是如何运作的。
fetch('https://pokeapi.co/api/v2/pokemon/ditto')
.then(response => console.log(response))
.catch(error => console.error(error));
console.log('this comes first though');
这里,我们使用内置的fetch API来调用PokeAPI并获取结果。即使您使用axios或GraphQL客户端,实现方式也相同。
fetch API 返回一个 Promise 对象,你可以对其调用 `get()`.then和`get()` 方法。error传递给 `get()` 的函数then会在请求fetch完成时调用,catch如果请求出错则会调用`get fetch()` 方法。请记住,请求会进入一个微队列,下一行代码会在之后执行。`get()`then或 ` errorget()` 回调函数只有在其他操作(包括 fetch 请求)完成后才会调用。
不,你保证。
那么,我们如何基于 Promise 创建自己的函数呢?
function serveDish() {
return new Promise(resolve => {
// An asynchronous function that gives you the dish back with a callback.
createDish(function(error, dish) {
if (error) {
throw error;
}
resolve(dish); // completed the operation and resolved the promise.
});
});
}
构造函数new Promise可以帮助你创建新的 Promise。如果你想将一个使用回调函数的程序转换为 Promise,或者只是想创建一个异步执行的 Promise,那么构造函数就很有用。如果 Promise 遇到错误,你可以抛出一个异常Error,然后catch在另一端也抛出同样的异常。
另一方:
serveDish()
.then(dish => console.log("Here's your dish", dish))
.catch(err => console.error('Things burned because of ', err));
接下来会发生什么?
您可以传递一个回调函数来接收创建操作then的响应,正如我们已经看到的。resolvePromise
让我们把一些承诺串联起来
但真正的优势Promises在于你可以将它们串联起来。
learnCooking()
.then(recipes => createDish(recipes))
.then(dish => inviteNeighbours(dish))
.then(dish => serveDish(dish))
.then(servedDish => getFeedback(servedDish))
.catch(err => console.error('Something went wrong! 🔥'));
这叫做 Promise 链式调用,你可以链接任意数量的 Promise,只要在前一个 then 语句中返回一个 Promise 即可。这比看起来要容易得多,因为基本类型会自动转换为 Promise。如果你想显式地将某些内容转换为 Promise,你可以这样做:
Promise.resolve(41);
有很多承诺要兑现。
到目前为止,我们已经了解了如何处理单个 Promise 并将其结果串联起来。但是,如果有多个 Promise,并且需要等待所有 Promise 都完成后才能执行,该怎么办呢?这时就需要Promise.all用到 Promise 了。
例如,你通过研究食谱制作了多道菜肴。
const dishes = ['names', 'of', 'your', 'favorite', 'dishes', 'go', 'here'];
// map returns the promise and forms dishesPromise array
const dishesPromise = dishes.map(dish => createDish(dish));
// You want to wait for all dishes to complete cooking before you invite neighbours
Promise.all(dishesPromise).then(dishes => inviteNeighbours(dishes));
Promise.all它接受一个 Promise 数组作为参数,then当所有 Promise 都完成后,该数组上的回调函数就会执行。then回调函数的参数是一个包含所有 Promise 结果的数组。
虽然Promise.all是最常用的方法,但还有其他方法可以帮助你处理多个 Promise 并采取相应的操作。你可以在 MDN 上找到所有这些方法。
笔记
then本文忽略了第二个参数。该参数会在 Promise 被拒绝时返回结果。这种情况很少见。如果您想拒绝一个 Promise,最好抛出一个错误,因为最终用户可以链式调用多个 Promise,并catch用一个 catch 块处理所有错误。添加多个函数then会造成混淆。
文章来源:https://dev.to/boywithsilverwings/promises-javascript-concepts-293c