Promises 和 Await 如何在 Javascript 中工作

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);
})

上面的示例在控制台记录输出之前等待来自网页的响应。这意味着我们可以等待另一台服务器的响应,然后再继续执行特定功能。