search
HomeWeb Front-endJS TutorialDetailed explanation of Promise and Async in JS

Detailed explanation of Promise and Async in JS

May 20, 2020 am 10:31 AM
asyncphppromise

Detailed explanation of Promise and Async in JS

Because JavaScript is a single-threaded language, synchronous code can only execute one line at a time. This means that if the sync code takes longer than an instant to run, it will stop the rest of the code from running until it completes. To prevent code with an uncertain runtime from preventing other code from running, we need to use asynchronous code.

Promise

For this we can use Promise in our code. Promise represents an object whose process runs for an indeterminate amount of time and whose outcome may be success or failure. To create a promise in JavaScript, we use the constructor of the Promise object to create the promise. The Promise constructor accepts an execution function with resolve and reject parameters. Both parameters are also functions, which allow us to call back promise completion (a successful call returns a value) or rejection (returns an error value and marks the promise as failed). The return value of the function is ignored. Therefore, promise can only return promises.

For example, we define a promise in JavaScript like the following code:

const promise = new Promise((resolve, reject) => {  
  setTimeout(() => resolve('abc'), 1000);  
});

The above code will create a promise that returns abc after one second. Because the setTimeout we run is a fulfillment promise that returns abc after one second within the executor function, it is asynchronous code. We cannot return the value abc in setTimeout's callback function, so we have to call resolve('abc') to get the parsed value. We can use the then function to access the return value of a completed promise. The then function accepts a callback function that takes the return value of the fulfilled promise as a parameter. You can get the value you want. For example, we can do this:

const promise = new Promise((resolve, reject) => {  
  setTimeout(() => resolve('abc'), 1000);  
});
promise.then((val) => {  
  console.log(val);  
})

When we run the above code, we should be able to get the record abc. As we can see, a promise provides a value when the resolve function is called after it completes.

A promise has three states. In the initial state, the promise neither succeeds nor fails. Completed status means the operation completed successfully. Or a failure status, which means that the promise operation failed.

A pending promise can be fulfilled by returning a value or fail with an error. When the promise is completed, the then function will get the corresponding return value and pass it to the callback function of the then function to call. If the promise fails, we can choose to use the catch function to capture the error, which can also pass an error to the callback function. Both then and catch return a promise, so they can be chained together.

For example, we can write:

const promise = (num) => {  
  return new Promise((resolve, reject) => {  
    setTimeout(() => {  
      if (num === 1) {  
        resolve('resolved')  
      } else {  
        reject('rejected')  
      }  
    }, 1000);  
  });  
}
promise(1)  
  .then((val) => {  
    console.log(val);  
  })  
  .catch((error) => {  
    console.log(error);  
  })promise(2)  
  .then((val) => {  
    console.log(val);  
  })  
  .catch((error) => {  
    console.log(error);  
  })

In the above code, we have a function promise, which returns a JavaScript promise that completes the promise with the resolved value when num is 1, The promise is rejected with the error rejected when num is not 1. So we run:

promise(1)  
  .then((val) => {  
    console.log(val);  
  })  
  .catch((error) => {  
    console.log(error);  
  })

Then the then function runs, and since num is 1, the promise(1) function call returns that the promise is fulfilled, and the resolved value is available in val. So when we run console.log(val), we get resolved. When we run the following code:

promise(2)  
  .then((val) => {  
    console.log(val);  
  })  
  .catch((error) => {  
    console.log(error);  
  })

catch will run because the promise(2) function call failed to return a promise and the rejected error value is available and set to error. So when we run console.log(error) we get rejected output.

A JavaScript promise object has the following properties: length and prototype. length is the number of constructor arguments, which is set to 1 and is always one. The prototype property represents the prototype of the promise object.

promise also has a finally method that runs code regardless of whether the promise is completed or failed. The finally method accepts a callback function as a parameter and can run any code you want to run, and it can be executed regardless of the result of the promise. For example, we run:

Promise.reject('error')  
  .then((value) => {  
    console.log(value);  
  })  
  .catch((error) => {  
    console.log(error);  
  })  
  .finally(() => {  
    console.log('finally runs');  
  })

Then we get error and finally runs records because the original promise got error and was rejected. Then run all the code in the finally method.

The main benefit of using promises is that when writing asynchronous code, we can use promises to run them sequentially. To do this, we can chain promises using the then function. The then function receives a callback function and runs it after the promise completes. It also accepts a second parameter after the promise is rejected. To use promises in chains, we must make its first callback function then function return another promise. If we don't want to chain another promise to an existing promise, we can return other values, just like none. We can return a value that will be available in the next then function. It can also throw an error. Then the promise returned by then will be rejected with an error. It can also return a fulfilled or rejected promise, its completed value will be obtained when blocking the then function linked after it, or the error reason will be obtained in the callback of the catch function.

For example, we can write:

Promise.resolve(1)  
  .then(val => {  
    console.log(val);  
    return Promise.resolve(2)  
  })  
  .then(val => {  
    console.log(val);  
  })Promise.resolve(1)  
  .then(val => {  
    console.log(val);  
    return Promise.reject('error')  
  })  
  .then(val => {  
    console.log(val);  
  })  
  .catch(error => console.log(error));Promise.resolve(1)  
  .then(val => {  
    console.log(val);  
    throw new Error('error');  
  })  
  .then(val => {  
    console.log(val);  
  })  
  .catch(error => console.log(error));

在第一个例子中,我们链式调用 promise,并且都 resolve 一个值。所有的 promise 都准备返回为值。在第二个和最后一个例子中,我们拒绝了第二个 promise 或抛出一个错误。它们都做了同样的事情。第二个 promise 被拒绝了,并且错误原因会被回调函数 catch 函数记录下来。我们还可以链接挂起状态的 promise,如下方代码所示:

const promise1 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(1), 1000);  
});
const promise2 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(2), 1000);  
});
promise1  
  .then(val => {  
    console.log(val);  
    return promise2;  
  })  
  .then(val => {  
    console.log(val);  
  })  
  .catch(error => console.log(error));

回调函数 then 函数返回了 promise2,这是一个挂起状态的 promise。

方法

JavaScript 的 promise 有以下方法。

Promise.all (可迭代对象)

Promise.all 接受一个可迭代对象,该对象允许我们在某些计算机上并行运行多个 promise,并在其他计算机上连续运行多个 promise。这对于运行多个不依赖于彼此的值的 promise 非常方便。它接受一个包含 promise 的列表 (通常是一个数组) 的可迭代对象,然后返回一个 Promise,这个 Promise 在可迭代对象中的 promise 被解析时解析。

例如,我们像下面这样写代码,使用 Promise.all 来运行多个 promise:

const promise1 = Promise.resolve(1);  
const promise2 = 2;  
const promise3 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(3), 1000);  
});  
Promise.all([promise1, promise2, promise3])  
  .then((values) => {  
    console.log(values);  
  });

如果我们运行了上方的代码,然后 console.log 应该会记录下 [1,2,3]。如我们所见,只有所有的 promise 都完成后返回它的解析值。如果其中的拒绝了,我们不会得到任何解析值。相反,我们将得到由被拒绝的 promise 返回的任何错误值。它将会在第一个被拒绝的 promise 处停止,并且发送值给回调函数 catch 函数。例如,如果我们这样:

const promise1 = Promise.resolve(1);  
const promise2 = Promise.reject(2);  
const promise3 = new Promise((resolve, reject) => {  
  setTimeout(() => reject(3), 1000);  
});  
Promise.all([promise1, promise2, promise3])  
  .then((values) => {  
    console.log(values);  
  })  
  .catch(error => {  
    console.log(error);  
  });

然后我们可以在回调函数 catch 函数的 console.log 中得到两个记录。

Promise.allSettled

Promise.allSettled 返回一个 promise,该 promise 的解析在所有的 promise 解析完或拒绝后。它接受带有一组 promise 的可迭代对象,例如,一个 promise 数组。返回的 promise 的解析值是每个 promise 的最终状态的数组。例如,假设我们有:

const promise1 = Promise.resolve(1);  
const promise2 = Promise.reject(2);  
const promise3 = new Promise((resolve, reject) => {  
  setTimeout(() => reject(3), 1000);  
});  
Promise.allSettled([promise1, promise2, promise3])  
  .then((values) => {  
    console.log(values);  
  })

若我们运行上方代码,我们将获得一个包含三个条目的数组,每个条目都是一个对象,该对象有已经完成 promise 的 status 和 value 属性以及被拒绝的 promise 的 status 和 reason 属性。例如,上面的代码会记录 {status: “fulfilled”, value: 1},{status: “rejected”, reason: 2},{status: “rejected”, reason: 3}。 fulfilled 状态记录的是成功的 promise,rejected 状态为被拒绝的 promise。

Promise.race

Promise.race 方法返回一个 promise,该 promise 会解析首先完成的 promise 的解析值。它接受一个带有 promise 集合的可迭代对象,例如,一个 promise 数组。如果传入的可迭代对象为空,则返回的 promise 将一直挂起。若可迭代对象包含一个或多个非 promise 值或者已经完成的 promise,Promise.race 将会返回这些条目中的第一个。例如,我们有:

const promise1 = Promise.resolve(1);  
const promise2 = Promise.resolve(2);  
const promise3 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(3), 1000);  
});  
Promise.race([promise1, promise2, promise3])  
  .then((values) => {  
    console.log(values);  
  })

然后我们看到 1 会被记录 。那是因为 promise1 是第一个被解析的,那是因为它是在下一行运行之前就被解析了。同样,如果我们的数组中有一个非 promise 值作为参数进行传入,如下代码所示:

const promise1 = 1;  
const promise2 = Promise.resolve(2);  
const promise3 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(3), 1000);  
});  
Promise.race([promise1, promise2, promise3])  
  .then((values) => {  
    console.log(values);  
  })

然后我们会得到相同的记录,因为它是我们传递给 Promise.race 方法的数组中的非 promise 值。同步代码始终运行在异步代码之前,而不论同步代码在哪里。如果我们有:

const promise1 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(1), 2000);  
});
const promise2 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(2), 1000);  
});
const promise3 = 3;  
Promise.race([promise1, promise2, promise3])  
  .then((values) => {  
    console.log(values);  
  })

然后我们记录下 3,因为 setTimeout 将回调函数放入队列中以便稍后运行,所以它将比同步代码更晚执行。

最后,如果我们有:

const promise1 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(1), 2000);  
}); 
const promise2 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(2), 1000);  
});
Promise.race([promise1, promise2])  
  .then((values) => {  
    console.log(values);  
  })

然后我们在控制台中得到记录 2,因为在一秒解析的 promise 要比两秒解析的 promise 更早解析。

Promise.reject

Promise.reject 返回一个因某种原因拒绝的 promise。拒绝带有 Error 的实例对象的 promise 非常有用。例如,如果我们有以下代码:

Promise.reject(new Error('rejected'))  
  .then((value) => {  
    console.log(value);  
  })  
  .catch((error) => {  
    console.log(error);  
  })

然后我们得到 rejected 记录。

Promise.resolve

Promise.resolve 返回一个已解析为传入 resolve 函数参数的值的 promise。我们也可以传递一个带有 then 属性的对象,它的值是 promise 的回调函数。如果该值具有 then 方法,则将使用 then 函数完成 promise。也就是说,then 函数值的第一个参数与 resolve 相同,以及第二个参数与 reject 相同。例如,我们可以编写如下代码:

Promise.resolve(1)  
  .then((value) => {  
    console.log(value);  
  })

然后我们得到 1 记录,因为 1 是我们传递给 resolve 函数来返后具有解析值 1 的承诺的值。

如果我们传入的对象内部带有 then 方法,如下代码所示:

Promise.resolve({  
    then(resolve, reject) {  
      resolve(1);  
    }  
  })  
  .then((value) => {  
    console.log(value);  
  })

然后我们得到记录的值 1。这是因为 Promise.resolve 函数将运行 then 函数,设置为 “then” 属性的函数的 “resolve” 参数将被假定为承诺中称为 “resolve” 函数的函数。并将该函数的 resolve 参数设置为 then 属性可以看作 promise 中一个叫做 resolve 函数。如果我们将传入 then 中的对象替换为 inject 函数,然后我们就可以得到被拒绝的 promise。代码如下所示:

Promise.resolve({  
    then(resolve, reject) {  
      reject('error');  
    }  
  })  
  .then((value) => {  
    console.log(value);  
  })  
  .catch((error) => {  
    console.log(error);  
  })

在上面的代码中,我们会得到 error 记录,这是因为 promise 被拒绝了。

Async 和 Await

使用 async 和 await,我们可以缩短 promise 代码。使用 async 和 await 之前前,我们必须得用 then 函数并且在 then 函数中放入回调函数作为所有的参数。这就使得我们有很多 promise 时代码冗长至极。相反,我们可以使用 async 和 await 语法来替代 then 函数以及相关回调。例如,我们可将以下代码缩短为:

const promise1 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(1), 2000);  
});
const promise2 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(2), 1000);  
});
promise1  
  .then((val1) => {  
    console.log(val1);  
    return promise2;  
  })  
  .then((val2) => {  
    console.log(val2);  
  })

写成:

const promise1 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(1), 2000);  
});  
const promise2 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(2), 1000);  
});
(async () => {  
  const val1 = await promise1;  
  console.log(val1)  
  const val2 = await promise2;  
  console.log(val2)  
})()

我们使用 await 来替换 then 和回调函数。然后,我们就可以将每个 promise 的解析值分配为变量。注意,如果我们为 promise 代码使用 await,那么我们必须像上例那样添加 async 到函数签名中。为了捕获错误,我们使用 catch 子句取代链式 catch 函数。另外,我们没有在底部链式调用 finally 函数以在 promise 结束时运行代码,而是在 catch 子句后使用 finally 子句。

例如,我们可以这样写:

const promise1 = new Promise((resolve, reject) => {  
  setTimeout(() => resolve(1), 2000);  
});  
const promise2 = new Promise((resolve, reject) => {  
  setTimeout(() => reject('error'), 1000);  
});
(async () => {  
  try {  
    const val1 = await promise1;  
    console.log(val1)  
    const val2 = await promise2;  
    console.log(val2)  
  } catch (error) {  
    console.log(error)  
  } finally {  
    console.log('finally runs');  
  }})()

在上面的代码中,我们获得了分配给变量的 promise 的解析值,而不是在 then 函数的回调中获取值,例如在 const response = await promise1 上面的一行。另外,我们使用 try...catch...finally 块来捕获被拒绝的 promise 的错误,以及 finally 子句替代 finally 函数,其无论 promise 执行结果如何,该代码都可以运行。

想其他使用 promise 的函数一样,async 函数始终返回 promise,并且不能返回其他任何东西。在上面的示例中,我们证明了与使用带有回调函数作为参数传递的 then 函数相比,我们可以更短的方式使用 promise。

结束语

使用 promise,让我们编写异步代码更容易。promise 是表示一个处理的运行时间不确定并且结果会成功也会失败的对象。在 JavaScript 中创建一个 promises,我们使用 Promise 对象,该对象是用于创建 promise 的构造函数。

Promise 构造函数接受一个拥有 resolve 和 reject 参数的执行函数。两个参数都是函数,它们让我们可以回调 promise 完成(成功调用得到返回值)或者拒绝(返回错误值并标记 promise 失败)。 The 函数的返回值被忽略。因此,promise 只能返回 promise。

因为 promise 返回 promise,所以 promise 是可链式调用。promise 的 then 函数可以抛出一个错误,返回解析值,或者其他 promise(挂起、已完成或已拒绝的 promise)。

推荐教程:《PHP教程

The above is the detailed content of Detailed explanation of Promise and Async in JS. For more information, please follow other related articles on the PHP Chinese website!

Statement
This article is reproduced at:learnku. If there is any infringement, please contact admin@php.cn delete
Understanding the JavaScript Engine: Implementation DetailsUnderstanding the JavaScript Engine: Implementation DetailsApr 17, 2025 am 12:05 AM

Understanding how JavaScript engine works internally is important to developers because it helps write more efficient code and understand performance bottlenecks and optimization strategies. 1) The engine's workflow includes three stages: parsing, compiling and execution; 2) During the execution process, the engine will perform dynamic optimization, such as inline cache and hidden classes; 3) Best practices include avoiding global variables, optimizing loops, using const and lets, and avoiding excessive use of closures.

Python vs. JavaScript: The Learning Curve and Ease of UsePython vs. JavaScript: The Learning Curve and Ease of UseApr 16, 2025 am 12:12 AM

Python is more suitable for beginners, with a smooth learning curve and concise syntax; JavaScript is suitable for front-end development, with a steep learning curve and flexible syntax. 1. Python syntax is intuitive and suitable for data science and back-end development. 2. JavaScript is flexible and widely used in front-end and server-side programming.

Python vs. JavaScript: Community, Libraries, and ResourcesPython vs. JavaScript: Community, Libraries, and ResourcesApr 15, 2025 am 12:16 AM

Python and JavaScript have their own advantages and disadvantages in terms of community, libraries and resources. 1) The Python community is friendly and suitable for beginners, but the front-end development resources are not as rich as JavaScript. 2) Python is powerful in data science and machine learning libraries, while JavaScript is better in front-end development libraries and frameworks. 3) Both have rich learning resources, but Python is suitable for starting with official documents, while JavaScript is better with MDNWebDocs. The choice should be based on project needs and personal interests.

From C/C   to JavaScript: How It All WorksFrom C/C to JavaScript: How It All WorksApr 14, 2025 am 12:05 AM

The shift from C/C to JavaScript requires adapting to dynamic typing, garbage collection and asynchronous programming. 1) C/C is a statically typed language that requires manual memory management, while JavaScript is dynamically typed and garbage collection is automatically processed. 2) C/C needs to be compiled into machine code, while JavaScript is an interpreted language. 3) JavaScript introduces concepts such as closures, prototype chains and Promise, which enhances flexibility and asynchronous programming capabilities.

JavaScript Engines: Comparing ImplementationsJavaScript Engines: Comparing ImplementationsApr 13, 2025 am 12:05 AM

Different JavaScript engines have different effects when parsing and executing JavaScript code, because the implementation principles and optimization strategies of each engine differ. 1. Lexical analysis: convert source code into lexical unit. 2. Grammar analysis: Generate an abstract syntax tree. 3. Optimization and compilation: Generate machine code through the JIT compiler. 4. Execute: Run the machine code. V8 engine optimizes through instant compilation and hidden class, SpiderMonkey uses a type inference system, resulting in different performance performance on the same code.

Beyond the Browser: JavaScript in the Real WorldBeyond the Browser: JavaScript in the Real WorldApr 12, 2025 am 12:06 AM

JavaScript's applications in the real world include server-side programming, mobile application development and Internet of Things control: 1. Server-side programming is realized through Node.js, suitable for high concurrent request processing. 2. Mobile application development is carried out through ReactNative and supports cross-platform deployment. 3. Used for IoT device control through Johnny-Five library, suitable for hardware interaction.

Building a Multi-Tenant SaaS Application with Next.js (Backend Integration)Building a Multi-Tenant SaaS Application with Next.js (Backend Integration)Apr 11, 2025 am 08:23 AM

I built a functional multi-tenant SaaS application (an EdTech app) with your everyday tech tool and you can do the same. First, what’s a multi-tenant SaaS application? Multi-tenant SaaS applications let you serve multiple customers from a sing

How to Build a Multi-Tenant SaaS Application with Next.js (Frontend Integration)How to Build a Multi-Tenant SaaS Application with Next.js (Frontend Integration)Apr 11, 2025 am 08:22 AM

This article demonstrates frontend integration with a backend secured by Permit, building a functional EdTech SaaS application using Next.js. The frontend fetches user permissions to control UI visibility and ensures API requests adhere to role-base

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
1 months agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
1 months agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
1 months agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Chat Commands and How to Use Them
1 months agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

SecLists

SecLists

SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.

PhpStorm Mac version

PhpStorm Mac version

The latest (2018.2.1) professional PHP integrated development tool

DVWA

DVWA

Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software

Dreamweaver Mac version

Dreamweaver Mac version

Visual web development tools

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools