本文将解释 JavaScript 处理异步操作所依赖的基本概念。这些概念包括 Callback 函数、Promise 和 Async 的使用,以及 Await 在 JavaScript 中处理不同的操作。
在对这三者进行比较之前,我们先简单了解一下同步(阻塞)和异步(非阻塞)。
为了便于理解,让我们举一个现实生活中的例子,便于解释异步和同步之间的区别。
想象一下,我们去一家餐馆,一个服务员来到一张桌子前,拿走你的订单,把它送到厨房。让我们将整个过程分为几个步骤
餐桌必须等待厨师做一顿饭,然后才能为另一张桌子服务。这就是我们所说的异步或非阻塞架构。在这里,服务员就像一个被分配来处理请求的线程。因此,单个线程用于处理多个请求。
与非阻塞或异步架构相比,我们有阻塞或同步架构。让我们看看它是如何工作的。所以回到餐厅的例子,假设你去另一家餐厅,在这家餐厅,一个服务员被分配给你。他接过你的订单,把它交给厨房。现在他坐在厨房里等着厨师为你准备饭菜,这次他没有做任何其他事情,他只是在等待,在你的饭菜准备好之前,他不会从另一张桌子上接受任何订单。这就是我们所说的同步或阻塞架构。
现在,第一个餐厅示例表示一个异步过程,因为您不必等待,服务员从一张桌子上接单,然后转到下一张桌子接单。而第二个示例餐厅表示同步操作,因为您必须等到资源(在本例中为服务员)可以与您一起继续。这是同步和异步进程之间唯一、最根本的区别。
在 JavaScript 中处理异步代码有不同的方法。这些是回调、promise 和 async/await。
在 JavaScript 中,函数是对象,因此我们可以将对象作为参数传递给函数。
我们以回调函数为例:
function printString(){
console.log("callback");
setTimeout(function() { console.log("back"); }, 500);
console.log("callback")
}
printString();
如果这是同步代码,我们将遇到以下输出。
callback
back
callback
但是 setTimeout 是一个异步函数,那么上面代码的输出将是:
callback
callback
back
JavaScript 中有一个名为“setTimeout”的内置方法,它在给定的时间段(以毫秒为单位)后调用函数。
换言之,消息函数是在发生某些事情之后(在本例中经过 5 秒后)调用的,而不是在发生之前调用的。
JavaScript 中的Promise,您可以将其视为现实生活许下的 “承诺” 。当我们在现实生活中做出承诺时,这意味着我们将来会做某事,因为承诺只能为未来做出。
承诺有两种可能的结果:要么你信守诺言,要么不信守诺言。
Promise 的基本原理同样适用于 JavaScript。当我们在 JavaScript 中定义一个 promise 时,它会在时机成熟时被解析,否则它将被拒绝。
promise 用于处理操作的异步结果。JavaScript 被设计为不等待异步代码块完全执行,然后代码的其他同步部分才能运行。使用 Promise,我们可以延迟代码块的执行,直到异步请求完成。这样,其他操作可以不间断地继续运行。
Promise 状态:
首先,Promise 是一个对象。Promise 对象有 3 种状态:
例如,当我们使用 Promise 从服务器请求数据时,它将处于待处理状态,直到我们收到数据。
如果我们从服务器获取信息,那么 Promise 将被成功解析,但如果我们没有获取信息,那么 Promise 将处于拒绝状态。
创建Promise:
首先,我们使用构造函数来创建一个 Promise 对象。promise 有两个参数,一个表示成功(解析),一个表示失败(拒绝):
const myFirstPromise = new Promise((resolve, reject) => {
const condition = true;
if(condition) {
setTimeout(function(){
resolve("Promise 成功!");
}, 500);
} else {
reject('Promise 拒绝!');
}
});
在上面的 Promise如果Condition 为 true,解析返回 “Promise 成功 ”的 promise,否则返回错误 “Promise 拒绝”。现在我们已经创建了第一个 Promise,现在让我们使用它。
使用 Promise:
要使用上述内容,请创建 Promise,我们用于解决和拒绝。then()catch()
myFirstPromise
.then((successMsg) => {
console.log(successMsg);
})
.catch((errorMsg) => {
console.log(errorMsg);
});
让我们更进一步:
const demoPromise= function() {
myFirstPromise
.then((successMsg) => {
console.log("Success:" + successMsg);
})
.catch((errorMsg) => {
console.log("Error:" + errorMsg);
})
}
demoPromise();
在我们创建的承诺条件中,条件是“true”,我们调用 demoPromise(),然后我们的控制台日志显示:
Success: Promise 成功!
因此,如果 promise 被拒绝,它将跳转到该方法,这次我们将在控制台上看到一条不同的消息。catch()
Error: Promise 拒绝!
Await 基本上是 Promise 的语法糖。它使您的异步代码看起来更像是同步/过程代码,这更容易被人类理解。
Async 和 Await 的语法:
async function printMyAsync(){
await printString("one")
await printString("two")
await printString("three")
}
您可以看到,我们为包装函数 printMyAsync 使用了 “async” 关键字。这让 JavaScript 知道我们使用的是 async/await 语法,如果你想使用 Await,这也是必要的。我们可以说 await 只与异步函数一起使用。
await
关键字用于异步函数,以确保异步函数中返回的所有 promise 都是同步的,即。他们互相等待。Await 消除了在 .then()
和 .catch()
中使用回调。在使用 async 和 await 时,async 在返回 promise 时被预置,await 在调用 promise 时被预置。try 和 catch 也用于获取异步函数的拒绝值。
让我们举个例子来理解 Promise 的 Async 和 Await:
const helloPromise = function() {
return new Promise(function(resolve, reject) {
const message = "hello";
resolve(message)
});
}
async function demoPromise() {
try {
let message = await helloPromise();
console.log(message);
}
catch(error){
console.log("Error:" + error.message);
}
}
demoPromise();
根据我们的用例,我们可以选择这种方法中的任何一种。由于 async/await 封装在 Promise 之上,因此它支持所有与 Promise 相关的功能。因此,在将 callback 与 Promise 进行比较时,Promise 比 callback 具有移动优势。列出其中的几个;
catch
块进行单个错误传播Promise
或 async/await
避免回调地狱Promise.all()
实现并行处理。(race(), allSettled() 和 any())
在比较经常用到的