Home  >  Article  >  Web Front-end  >  A deep dive into async functions in JavaScript

A deep dive into async functions in JavaScript

青灯夜游
青灯夜游forward
2022-11-03 20:36:441545browse

A deep dive into async functions in JavaScript

async function

The return value of the async function is the promise object, and the result of the promise object is determined by the return value of the async function execution. The async function can make asynchronous operations more convenient. In short, it is the syntactic sugar of Generator.

Define async function, the characteristic is that even if the internal return result of the function is not a promise object, the final return result of calling the function is still a promise object , the code is as follows: If the returned result is not a Promise object:

<script>
    async function fn(){
        // 返回的结果是字符串
        // return &#39;123&#39;
        // // 返回的结果是undefined
        // return;
        // 返回的结果是抛出一个异常
        throw new &#39;error&#39;
    }
    const result = fn()
    console.log(result);
</script>

If the returned result is a Promise object When, we can use the then method normally, as follows:

<script>
    async function fn(){
        return new Promise((resolve,reject)=>{
            // resolve(&#39;成功的数据&#39;)
            reject(&#39;失败的数据&#39;)
        })
    }
    const result = fn()
    // 调用 then 方法
    result.then((value)=>{
        console.log(value);
    },(reason)=>{
        console.log(reason); // 打印失败的数据
    })
</script>

await expression

Through the above introduction to async, I feel that its function is a bit tasteless, but in fact it is No, but async needs to be used together with await to achieve the effect of syntactic sugar.

Characteristics of await: await must be written in the async function

The expression on the right side of await Generally, it is a promise object

await returns the value of successful promise

If the promise of await fails, an exception will be thrown and needs to be captured and processed through try...catch

To put it bluntly: await is equivalent to the first callback function of the then method, only returning successful values, and failed values ​​need to be captured by try...catch. An error is thrown inside the async function, which will cause the returned Promise object to become rejected. The thrown error object will be received by the catch method callback function.

<script>
    const p = new Promise((resolve,reject)=>{
        // resolve(&#39;用户数据&#39;)
        reject(&#39;用户加载数据失败了&#39;)
    })
    async function fn(){
        // 为防止promise是失败的状态,加上try...catch进行异常捕获
        try {
            // await 返回的结果就是 promise 返回成功的值
            let result = await p
            console.log(result);
        } catch (error) {
            console.log(error);//因为是失败的状态,所以打印:用户加载数据失败了
        }
    }
    fn()
</script>

Summary:

(1)Promise behind the await command Object, the operation result may be rejected, so it is best to put the await command in the try...catch code block.

(2)If there are asynchronous operations behind multiple await commands, and if there is no subsequent relationship, it is best to let them trigger at the same time. For example: await Promise.all([a(), b()]), here is a brief mention

(3)await The command can only be used in async functions. If used in ordinary functions, an error will be reported.

(4)(Understand the operating principle of async) The async function can retain the running stack. When running an asynchronous task inside the ordinary function , if the asynchronous task ends, the ordinary function may have finished running long ago, and the context of the asynchronous task has disappeared. If the asynchronous task reports an error, the error stack will not include the ordinary function; while the asynchronous task inside the async function is running, the async function is paused executed, so once the asynchronous task inside the async function runs and an error is reported, the error stack will include the async function.

async uses the form

// 函数声明
async function foo() {}
 
// 函数表达式
const foo = async function () {};
 
// 对象的方法
let obj = { async foo() {} };
obj.foo().then(...)
 
// Class 的方法
class Storage {
  constructor() {
    this.cachePromise = caches.open(&#39;avatars&#39;);
  }
 
  async getAvatar(name) {
    const cache = await this.cachePromise;
    return cache.match(`/avatars/${name}.jpg`);
  }
}
 
const storage = new Storage();
storage.getAvatar(&#39;jake&#39;).then(…);
 
// 箭头函数
const foo = async () => {};

async reads the file

And the promise explained before reads the file content Similarly, we can also use async to read files. The code is as follows:

// 1.引入 fs 模块
const fs = require(&#39;fs&#39;)
 
// 2.读取文件
function index(){
    return new Promise((resolve,reject)=>{
        fs.readFile(&#39;./index.md&#39;,(err,data)=>{
            // 如果失败
            if(err) reject(err)
            // 如果成功
            resolve(data)
        })
    })
}
function index1(){
    return new Promise((resolve,reject)=>{
        fs.readFile(&#39;./index1.md&#39;,(err,data)=>{
            // 如果失败
            if(err) reject(err)
            // 如果成功
            resolve(data)
        })
    })
}
function index2(){
    return new Promise((resolve,reject)=>{
        fs.readFile(&#39;./index2.md&#39;,(err,data)=>{
            // 如果失败
            if(err) reject(err)
            // 如果成功
            resolve(data)
        })
    })
}
 
// 3.声明一个 async 函数
async function fn(){
    let i = await index()
    let i1 = await index1()
    let i2 = await index2()
    console.log(i.toString());
    console.log(i1.toString());
    console.log(i2.toString());
}
fn()

async sends AJAX request

and before Explain

promise sending ajax request

Similarly, we can also use async to send ajax request. The code is as follows:

<script>
    // 发送 AJAX请求,返回的结果是 Promise 对象
    function sendAjax(url){
        return new Promise((resolve,reject)=>{
            // 创建对象
            const x = new XMLHttpRequest()
 
            // 初始化
            x.open(&#39;GET&#39;,url)
 
            // 发送
            x.send()
 
            // 事件绑定
            x.onreadystatechange = function(){
                if(x.readyState === 4){
                    if(x.status >= 200 && x.status < 300){
                        // 如果响应成功
                        resolve(x.response)
                        // 如果响应失败
                        reject(x.status)
                    }
                }
            }
        })
    }
        
    // promise then 方法测试
    // const result = sendAjax("https://ai.baidu.com/").then(value=>{
    //     console.log(value);
    // },reason=>{})
    // async 与 await 测试
    async function fn(){
        // 发送 AJAX 请求
        let result = await sendAjax("https://ai.baidu.com/")
        console.log(result);
    }
    fn()
</script>

With generator )Compared with

, we found that the relationship between async and await is very similar to the relationship between Generator and yield. Friends who are not familiar with Generator can read my previous article:

Generator Explanation

; After comparison, we found that: async function is to replace the asterisk (*) of the Generator function with async, and replace yield with await. The code comparison is as follows:

<script>
    // Generator 函数
    function * person() {
        console.log(&#39;hello world&#39;);
        yield &#39;第一分隔线&#39; 
    
        console.log(&#39;hello world 1&#39;);
        yield &#39;第二分隔线&#39;
    
        console.log(&#39;hello world 2&#39;);
        yield &#39;第三分隔线&#39;
    }
    let iterator = person()
    // console.log(iterator); 打印的就是一个迭代器对象,里面有一个 next() 方法,我们借助next方法让它运行
    iterator.next()
    iterator.next()
    iterator.next()
 
    // async函数
    const person1 = async function (){
        console.log(&#39;hello world&#39;);
        await &#39;第一分隔线&#39; 
    
        console.log(&#39;hello world 1&#39;);
        await &#39;第二分隔线&#39;
    
        console.log(&#39;hello world 2&#39;);
        await &#39;第三分隔线&#39;
    }
    person1()
</script>

The implementation principle of the async function is to wrap the Generator function and the automatic executor in a function.

<script>
    async function fn(args) {}
    // 等同于
    function fn(args) {
        // spawn函数就是自动执行器
        return spawn(function* () {});
    }
</script>

We can analyze the writing characteristics and style of Generator and async code:

<script>
    // Generator 函数
    function Generator(a, b) {
        return spawn(function*() {
            let r = null;
            try {
                for(let k of b) {
                r = yield k(a);
                }
            } catch(e) {
                /* 忽略错误,继续执行 */
            }
            return r;
        });
    }
 
    // async 函数
    async function async(a, b) {
        let r = null;
        try {
            for(let k of b) {
            r = await k(a);
            }
        } catch(e) {
         /* 忽略错误,继续执行 */
        }
        return r;
    }
</script>

所以 async 函数的实现符合语义也很简洁,不用写Generator的自动执行器,改在语言底层提供,因此代码量少。 

从上文代码我们可以总结以下几点

(1)Generator函数执行需要借助执行器,而async函数自带执行器,即async不需要像生成器一样需要借助 next 方法才能执行,而是会自动执行。

(2)相比于生成器函数,我们可以看到 async 函数的语义更加清晰

(3)上面就说了,async函数可以接受Promise或者其他原始类型,而生成器函数yield命令后面只能是Promise对象或者Thunk函数。

(4)async函数返回值只能是Promise对象,而生成器函数返回值是 Iterator 对象

【推荐学习:javascript高级教程

The above is the detailed content of A deep dive into async functions in JavaScript. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:csdn.net. If there is any infringement, please contact admin@php.cn delete