ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScriptによる非同期処理解析

JavaScriptによる非同期処理解析

小云云
小云云オリジナル
2017-12-04 11:32:121702ブラウズ

非同期処理とは、非同期の手順に従って問題を処理することです。非同期処理と同期処理は対極にあり、それを生み出すものがマルチスレッドまたはマルチプロセスです。非同期処理のメリットは、デバイスの使用率が向上し、マクロレベルでのプログラムの動作効率が向上することですが、デメリットは、動作の競合やダーティデータの読み取りが発生しやすいことです。今回はJavaScriptの非同期処理について紹介します。

JavaScript の世界では、すべてのコードは単一のスレッドで実行されます。この「欠陥」のため、JavaScript のすべてのネットワーク操作とブラウザ イベントは非同期で実行する必要があります。非同期実行はコールバック関数を使用して実装できます

非同期操作は、将来の特定の時点で関数呼び出しをトリガーします

主流の非同期処理ソリューションには主に、コールバック関数 (CallBack)、Promise、Generator 関数、async/await が含まれます。

1. コールバック関数 (CallBack)

これは非同期プログラミングの最も基本的なメソッドです

最初のパラメーターはリクエストされた URL アドレスであり、2 番目のパラメーターはデータを取得するために使用されるとします。はコールバックです。 関数は次のとおりです。

function getData(url, callBack){    // 模拟发送网络请求
    setTimeout(()=> {        // 假设 res 就是返回的数据
        var res = {
            url: url,
            data: Math.random()
        }        // 执行回调,将数据作为参数传递
        callBack(res)
    }, 1000)
}

以下のように、サーバーに 3 回リクエストするシナリオを設定するとします。上記のコードの最初のリクエストの URL アドレスは /page/1?param=123 で、返される結果は res1 です。

2 番目のリクエストの URL アドレスは /page/2?param=${res1.data} で、これは最初のリクエストの res1.data に依存し、返される結果は res2` です。

3 番目のリクエストの URL アドレスは /page/3?param=${res2.data} で、これは 2 番目のリクエストの res2.data に依存し、返される結果は res3 です。

後続のリクエストは前のリクエストの結果に依存するため、次のリクエストは前のリクエストのコールバック関数内に記述することしかできず、よく言われる「コールバック地獄」が形成されます。

2. パブリッシュ/サブスクライブ

タスクが完了すると、シグナル センターにシグナルが「パブリッシュ」され、他のタスクがシグナル センターに「サブスクライブ」できるとします。シグナルは、いつ実行を開始できるかを知らせます。これは「パブリッシュ-サブスクライブ パターン」(パブリッシュ-サブスクライブ パターン) と呼ばれ、「オブザーバー パターン」(オブザーバー パターン) とも呼ばれます。次に示すのは、Ben Alman の Tiny Pub/Sub です。 jQuery 用のプラグイン

まず、f2 は「シグナル センター」にサブスクライブします。jQuery は「signal

getData('/page/1?param=123', (res1) => {    console.log(res1)
    getData(`/page/2?param=${res1.data}`, (res2) => {        console.log(res2)
        getData(`/page/3?param=${res2.data}`, (res3) => {            console.log(res3)
        })
    })
})
jQuery.subscribe("done", f2);

」このメソッドの性質は「イベント リスニング」に似ていますが、後者よりも大幅に優れています。なぜなら、「メッセージ センター」を見て、存在するシグナルの数と各シグナルの加入者数を確認することで、プログラムの動作を監視できるからです。

3. Promise

Promise は、従来のソリューションであるコールバック関数やイベントよりも合理的で強力です。いわゆる Promise は、特定のイベントの結果を格納するコンテナーです。 (通常は非同期操作) 将来終了します。構文的に言えば、Promise は非同期操作のメッセージを取得できるオブジェクトです。 Promise は統一された API を提供し、さまざまな非同期操作を同じ方法で処理できます。簡単に言えば、各非同期タスクが Promise オブジェクトを返し、そのオブジェクトにはコールバック関数を指定できる then メソッドが含まれます。

ここで、Promise を使用して上記のケースを再実装します。まず、データを非同期にリクエストするメソッドを Promise にカプセル化する必要があります

f1进行如下改写
function f1(){                setTimeout(function(){                        // f1的任务代码                        jQuery.publish("done");                }, 1000);}
jQuery.publish("done") 的意思是, f1 执行完成后,向”信号中心 "jQuery 发布 "done" 信号,从而引发f2的执行。 此外,f2完成执行后,也可以取消订阅( unsubscribe )
jQuery.unsubscribe("done", f2);

その後、リクエスト コードは次のように記述する必要があります

function getDataAsync(url){    return new Promise((resolve, reject) => {
        setTimeout(()=> {            var res = {
                url: url,
                data: Math.random()
            }
            resolve(res)
        }, 1000)
    })
}

その後、メソッドは新しい Promise オブジェクトを返します。 then メソッドの連鎖呼び出しは、CallBack コールバック地獄を回避します

。ただし、これは完璧ではありません。たとえば、多くの then ステートメントを追加する必要がある場合でも、各 then に対してコールバックを記述する必要があります。

シナリオがより複雑な場合、たとえば、後続の各リクエストが、前のリクエストの結果だけでなく、以前のすべてのリクエストの結果に依存する場合、シナリオはさらに複雑になります。 より良くするために、async/await を使用して実装する方法を見てみましょう

4. async/await

getDataAsync メソッドは次の通りです

getDataAsync('/page/1?param=123')
    .then(res1=> {        console.log(res1)        return getDataAsync(`/page/2?param=${res1.data}`)
    })
    .then(res2=> {        console.log(res2)        return getDataAsync(`/page/3?param=${res2.data}`)
    })
    .then(res3=> {        console.log(res3)
    })

ビジネスコードは次のとおりです

非同期関数 getData(){ var res1 = await getDataAsync('/page/1?param=123') console.log(res1) var res2 = await getDataAsync(`/page/2?param=${res1.data} `) console .log(res2) var res3 = await getDataAsync(`/page/2?param=${res2.data}`) console.log(res3)

}

asyncawait の使用は次のようであることがわかります。同期コードを書いています

Promise と比較してどう思いますか?非常に明確ですが、async/await は Promise に基づいています。実際、async で修飾されたメソッドは最終的に Promise を返すため、async/await は非同期構文シュガーを処理するために Generator 関数を使用していると見なすことができます。ジェネレーター関数は非同期を処理します

5. ジェネレーター


まず、非同期関数は次のように記述できます

function getDataAsync(url){    return new Promise((resolve, reject) => {
        setTimeout(()=> {            var res = {
                url: url,
                data: Math.random()
            }
            resolve(res)
        }, 1000)
    })
}

そして、それをステップごとに実行します

var g = getData()
g.next().value.then(res1=> {
    g.next(res1).value.then(res2=> {
        g.next(res2).value.then(()=> {
            g.next()
        })
    })
})

上面的代码,我们逐步调用遍历器的 next() 方法,由于每一个 next() 方法返回值的 value 属性为一个 Promise 对象

所以我们为其添加 then 方法, 在 then 方法里面接着运行 next 方法挪移遍历器指针,直到 Generator 函数运行完成,实际上,这个过程我们不必手动完成,可以封装成一个简单的执行器

function run(gen){    var g = gen()    function next(data){        var res = g.next(data)        if (res.done) return res.value
        res.value.then((data) => {
            next(data)
        })
    }
    next()
}

run 方法用来自动运行异步的 Generator 函数,其实就是一个递归的过程调用的过程。这样我们就不必手动执行 Generator 函数了。 有了 run 方法,我们只需要这样运行 getData 方法

run(getData)

这样,我们就可以把异步操作封装到 Generator 函数内部,使用 run 方法作为 Generator 函数的自执行器,来处理异步。其实我们不难发现, async/await 方法相比于 Generator 处理异步的方式,有很多相似的地方,只不过 async/await 在语义化方面更加明显,同时 async/await 不需要我们手写执行器,其内部已经帮我们封装好了,这就是为什么说 async/await 是 Generator 函数处理异步的语法糖了

以上内容就是关于JavaScript中的异步处理,希望能帮助到大家。

相关推荐:

PHP异步处理的实现方案

详谈 Jquery Ajax异步处理Json数据

php 异步处理

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

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。