JavaScript の非同期関数の詳細

青灯夜游
青灯夜游転載
2022-11-03 20:36:441595ブラウズ

JavaScript の非同期関数の詳細

async 関数

async 関数の戻り値は Promise オブジェクトであり、Promise オブジェクトの結果は戻り値によって決まります。非同期関数実行の値。 async 関数は非同期操作をより便利にするもので、一言で言えばジェネレーターの糖衣構文です。

非同期関数を定義します。その特徴は、 関数の内部戻り結果が Promise オブジェクトではない場合でも、関数呼び出しの最終的な戻り結果が次のとおりであることです。まだ Promise オブジェクト である場合、コードは次のとおりです: 返された結果が Promise オブジェクトではない場合:

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

If返された結果は Promise オブジェクトです。 この場合、次のように then メソッドを普通に使用できます。

<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 式

上記の async の紹介を通して、私は次のように感じました。その機能は少し味気ないですが、実際には「いいえ」ですが、糖衣構文の効果を実現するには、async を await と一緒に使用する必要があります。

await の特徴

: await は非同期関数内に記述する必要があります 右側の式await の側 一般に、これは Promise オブジェクトです。

await は、成功した Promise の値を返します。

await の Promise が失敗した場合、例外がスローされるため、try を通じてキャプチャして処理する必要があります。 ...catch

率直に言うと、await は then メソッドの最初のコールバック関数と同等であり、成功した値のみを返し、失敗した場合は返されます。値は try...catch で取得する必要があります。

非同期関数内でエラーがスローされ、返された Promise オブジェクトが拒否されます。スローされたエラー オブジェクトは、catch メソッドのコールバック関数によって受信されます。

<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>

概要

:

(1)await コマンドの背後にある約束オブジェクトの場合、操作結果が拒否される可能性があるため、try...catch コード ブロックに await コマンドを入れるのが最善です。

(2)複数の await コマンドの背後に非同期操作があり、後続の関係がない場合は、それらを同時にトリガーさせるのが最善です。 。

例: await Promise.all([a(), b()])、ここで簡単に説明します (3)

await このコマンドは非同期関数でのみ使用でき、通常の関数で使用するとエラーが報告されます。

(4)(

asyncの動作原理を理解する

) async関数は実行中のスタックを保持することができます。通常の関数内で、非同期タスクが終了した場合、通常の関数はずっと前に実行を終了している可能性があり、非同期タスクのコンテキストは消えています。非同期タスクがエラーを報告した場合、エラー スタックには通常の関数は含まれません。 async 関数内の非同期タスクが実行中である場合、async 関数は実行を一時停止しているため、async 関数内の非同期タスクが実行されてエラーが報告されると、エラー スタックには async 関数が含まれます。 async は形式を使用します

// 函数声明
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 はファイルを読み取ります

そして、前に説明した Promise はファイルを読み取りますcontent 同様に、async を使用してファイルを読み取ることもできます。コードは次のとおりです:

// 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

Explain 前

promise ajax リクエストの送信

同様に、async を使用して ajax リクエストを送信することもできます。コードは次のとおりです:
<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>

Generator を使用すると、

と比較して、async と await の関係が Generator と yield の関係に非常に似ていることがわかりました。Generator に詳しくない友人は、私の以前の記事を読んでください:

Generator 説明

; 比較した結果、async 関数は Generator 関数のアスタリスク (*) を async に置き換え、yield を await に置き換えることがわかりました。コードの比較は次のとおりです。
<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>

async 関数の実装原則は、ジェネレーター関数と自動エグゼキューターを関数内にラップすることです。

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

ジェネレーターと非同期コードの記述特性とスタイルを分析できます:

<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高级教程

以上がJavaScript の非同期関数の詳細の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcsdn.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。