Javascript 是一种异步语言。这意味着一行代码可以运行,并触发一个动作,而下一行运行。如果我们需要等待动作完成,那将成为一个问题。
一个完美的例子就是运行 API。假设我们使用 fetch 从 API 中获取数据,然后需要在下一行使用它:
const getPage = fetch('https://code8cn.com/api/importantData'); console.log(getPage); // Returns Promise {pending} or undefined const useData = getPage.json().showMeTheMoney; // Returns a type error.
所以我们尝试获取一个页面,然后使用该页面应该返回的数据。问题是获取请求仍在运行,而其他行已完成执行。fetch
异步运行,这意味着它会触发,并且在它试图得到它的答案时其他行可以继续。
我们必须以某种方式等待 fetch 完成,以获得我们需要的响应。
Await#
Await
是我们想要等待一行完成时使用的关键字,但它只在某些情况下有效:
- 在一个
async
函数中 - 当线路返回一个promise时
将来,我们将能够在async
函数之外使用 await,但现在您通常需要一个。要理解 await,我们需要理解 Promise。
Promises#
我们熟悉函数返回某些东西的概念。Promise 是一种返回类型,当我们调用resolve
或返回reject
结果时会返回一个值。为了解决这个问题,让我们看一个典型的 Promise 函数。
function myPromise() { return new Promise(resolve => { setTimeout(function() { resolve('Hey there'); }, 4000); }); } async function runMyPromise() { console.log(await myPromise()); // returns: Hey there }
resolve
表示这个特定Promises的返回值。如您所见,尽管我们在myPromise()
函数中说“嘿,那里”之前等待了 4 秒,但当我们await
为 promise 返回一个值时,我们仍然可以通过控制台记录其最终值。
要回答您的想法,是的,这确实会使代码停止 4 秒钟– 所以在使用 Promise 时要小心。停止呈现网页的 API 调用await
可能会导致更长的页面加载时间。
Rejections拒绝#
Promise 可以被解决或拒绝。在上面的例子中,我们只解析了函数——但是我们可以使用拒绝来给我们一些错误处理能力。
拒绝最好与then().catch()
表示法一起使用。
Then/Catch
返回一个 promise 的函数被称为 thennable。这意味着它们可以连接到它们的末端。只要 promise 得到解决,那么其中的任何内容都会触发。同样,catch()
将返回来自 Promise 的任何拒绝。这种格式的一个好处是我们不必使用async
函数。
我们来看一个例子:
function myPromise() { return new Promise((resolve, reject) => { setTimeout(function() { reject('Too Soon!') }, 2000); setTimeout(function() { resolve('Hey there'); }, 4000); }); } myPromise().then((data) => { console.log(`Success: ${data}`); }).catch((data) => { console.log(`Error: ${data}`); }); // The above returns: Error: Too Soon!
由于 2 秒后,我们reject
在 promise 上触发了一行,then/catch 子句拒绝了该 promise,并返回一个错误,该错误被传递到 catch 语句中。如果需要,这让我们可以在函数中进行错误处理。
Thennable 函数也是可链接的,最后一个函数的返回值然后传递给下一个函数——所以我们可以这样写:
function addTwo(x) { return new Promise(resolve => { setTimeout(function() { resolve(x + 2); }, 1000); }) } async function myFunction() { const Addition = await addTwo(2).then(data => data + 4).then(data => data + 10).then(data => data - 4); console.log(Addition) // returns: 14 }
在上面的示例中,我想通过控制台记录基于 Promise 的变量的值。如果我在 内执行其他所有then()
操作,那将没有问题,但由于我的控制台日志不在该then
子句之外,我们需要await
在该行上完成。
从那时起返回一个Promises,我们可以在执行任何控制台日志之前轻松等待所有添加完成。
现实生活中的例子:fetch()#
超时很有趣,但是这种东西在现实生活中的应用是什么?最有用的例子之一是fetch()
,一个获取任何 HTTP 请求响应的函数。Fetch 返回一个 Promise,因此我们可以轻松地等待数据从请求中返回,然后再继续执行下一行代码:
async function getFjolt() { const page = await fetch('https://code8cn.com/', { method: 'GET' }); return page; } getFjolt().then((data) => { console.log(data); })
上面的示例在控制台记录输出之前等待来自网页的响应。这意味着我们可以等待另一台服务器的响应,然后再继续执行特定功能。