目次
JavaScript の非同期とコールバック
1. はじめに
2. 非同期関数
3. コールバック関数
四、回调的回调
五、回调地狱
ホームページ ウェブフロントエンド jsチュートリアル JavaScriptにおける非同期とコールバックの基本概念とコールバック地獄現象

JavaScriptにおける非同期とコールバックの基本概念とコールバック地獄現象

Aug 17, 2022 pm 06:05 PM
javascript

この記事では、javascript に関する関連知識を紹介します。主に、JavaScript における非同期とコールバックの基本的な概念と、コールバック地獄の現象について紹介します。この記事では、主に、非同期とコールバックの基本的な概念を紹介します。 callbacks. 、この 2 つは JavaScript の核となるコンテンツです。一緒に見ていきましょう。皆さんのお役に立てれば幸いです。

JavaScriptにおける非同期とコールバックの基本概念とコールバック地獄現象

[関連する推奨事項: JavaScript ビデオ チュートリアルWeb フロントエンド]

JavaScript の非同期とコールバック

1. はじめに

この記事の内容を学ぶ前に、まず非同期の概念を理解する必要があります。最初に強調すべきことは、本質的な違いがあるということです。 非同期と並列の間

  • パラレルとは、通常、並列コンピューティングを指します。これは、複数の命令が同時に実行されることを意味します。これらの命令は、同じ CPU の複数のコア、または複数のコアで実行される場合があります。 CPU、複数の物理ホスト、さらには複数のネットワーク。
  • 同期とは一般に、あらかじめ決められた順序でタスクを実行することを指し、前のタスクが完了した場合にのみ次のタスクが実行されます。
  • 非同期 (同期に対応) 非同期とは、CPU が現在のタスクを一時的に保留し、最初に次のタスクを処理し、コールバック通知を受信した後に前のタスクに戻ることを指します。前のタスク。タスクは実行を継続します。プロセス全体に 2 番目のスレッドが参加する必要はありません。

並列処理、同期、非同期を説明するには、図を使用する方が直感的かもしれません。処理する必要がある 2 つのタスク A と B があるとします。並列、同期、非同期の処理方法は次のようになります。実行方法は次のとおりです。

2. 非同期関数

JavaScript は多くの機能を提供します。非同期関数 関数、これらの関数を使用すると、非同期タスクを簡単に実行できます。つまり、今タスク (関数) の実行を開始しますが、タスクは後で完了し、具体的な完了時刻は明確ではありません。

たとえば、setTimeout 関数は非常に典型的な非同期関数です。さらに、fs.readFilefs.writeFile も非同期です。機能。

ファイル コピー関数 copyFile(from,to):

const fs = require('fs')

function copyFile(from, to) {
    fs.readFile(from, (err, data) => {
        if (err) {
            console.log(err.message)
            return
        }
        fs.writeFile(to, data, (err) => {
            if (err) {
                console.log(err.message)
                return
            }
            console.log('Copy finished')
        })
    })
}
ログイン後にコピー

FunctioncopyFile## のカスタマイズなど、非同期タスク ケースを自分で定義できます。まず、パラメータ from からファイル データを読み取り、次にパラメータ to が指すファイルにデータを書き込みます。

copyFile は次のように呼び出すことができます:

copyFile('./from.txt','./to.txt')//复制文件
ログイン後にコピー

現時点で

copyFile(...) の背後に他のコードがある場合、プログラム copyFile の実行が終了するのを待たずに、直接実行します。プログラムは、ファイル コピー タスクがいつ終了するかを気にしません。

copyFile('./from.txt','./to.txt')
//下面的代码不会等待上面的代码执行结束
...
ログイン後にコピー

ここまではすべて正常に見えますが、

copyFile(...) 関数の後にファイル ./to.txt に直接アクセスするとどうなるでしょうか。 の内容にアクセスしますか?

これは、次のようにコピーされたコンテンツを読み取りません:

copyFile('./from.txt','./to.txt')
fs.readFile('./to.txt',(err,data)=>{
    ...
})
ログイン後にコピー

プログラムを実行する前に

./to.txt ファイルが作成されていない場合は、次のエラーが発生しました:

PS E:\Code\Node\demos\03-callback>node .\index.js

finished
Copy completed
PS E:\コード \Node\demos\03-callback> ノード .\index.js
エラー: ENOENT: そのようなファイルまたはディレクトリはありません。'E:\Code\Node\demos\03-callback\to.txt' を開いてください
コピー完了

./to.txtが存在しても、コピーした内容は読み取れません。

この現象の理由は次のとおりです:

copyFile(...) は非同期で実行されます。プログラムが copyFile(...) 関数を実行した後、コピーが完了するのを待たずにコピーを直接実行すると、ファイル ./to.txt が存在しないというエラー、またはファイルの内容が空であるというエラーが発生します (ファイルが存在しない場合)あらかじめ作成しておきます)。

3. コールバック関数

非同期関数の具体的な実行終了時刻は決定できません (例:

readFile(from,to)##)。 # function 実行終了時間は、ファイル from のサイズに依存する可能性が高くなります。 それでは、問題は、

copyFile

実行の終わりをどのように正確に見つけて、to ファイルの内容を読み取ることができるかということです。 これにはコールバック関数の使用が必要です。

copyFile

関数を次のように変更できます: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>function copyFile(from, to, callback) { fs.readFile(from, (err, data) =&gt; { if (err) { console.log(err.message) return } fs.writeFile(to, data, (err) =&gt; { if (err) { console.log(err.message) return } console.log(&amp;#39;Copy finished&amp;#39;) callback()//当复制操作完成后调用回调函数 }) }) }</pre><div class="contentsignin">ログイン後にコピー</div></div>このようにして、直後にいくつかの操作を実行する必要がある場合、ファイルのコピーは完了しました。これらの操作をコールバック関数に書き込むことができます。

function copyFile(from, to, callback) {
    fs.readFile(from, (err, data) => {
        if (err) {
            console.log(err.message)
            return
        }
        fs.writeFile(to, data, (err) => {
            if (err) {
                console.log(err.message)
                return
            }
            console.log(&#39;Copy finished&#39;)
            callback()//当复制操作完成后调用回调函数
        })
    })
}
copyFile('./from.txt', './to.txt', function () {
    //传入一个回调函数,读取“to.txt”文件中的内容并输出
    fs.readFile('./to.txt', (err, data) => {
        if (err) {
            console.log(err.message)
            return
        }
        console.log(data.toString())
    })
})
ログイン後にコピー

./from.txt

ファイルを準備している場合は、上記のコードを直接実行できます。 : <blockquote><p>PS E:\Code\Node\demos\03-callback> node .\index.js<br/>Copy finished<br/>加入社区“仙宗”,和我一起修仙吧<br/>社区地址:http://t.csdn.cn/EKf1h</p></blockquote><p>这种编程方式被称为“基于回调”的异步编程风格,异步执行的函数应当提供一个回调参数用于在任务结束后调用。</p><p>这种风格在<code>JavaScript编程中普遍存在,例如文件读取函数fs.readFilefs.writeFile都是异步函数。

四、回调的回调

回调函数可以准确的在异步工作完成后处理后继事宜,如果我们需要依次执行多个异步操作,就需要嵌套回调函数。

案例场景:依次读取文件A和文件B

代码实现:

fs.readFile(&#39;./A.txt&#39;, (err, data) => {
    if (err) {
        console.log(err.message)
        return
    }
    console.log(&#39;读取文件A:&#39; + data.toString())
    fs.readFile(&#39;./B.txt&#39;, (err, data) => {
        if (err) {
            console.log(err.message)
            return
        }
        console.log("读取文件B:" + data.toString())
    })
})
ログイン後にコピー

执行效果:

PS E:\Code\Node\demos\03-callback> node .\index.js
读取文件A:仙宗无限好,只是缺了佬

读取文件B:要想入仙宗,链接不能少
http://t.csdn.cn/H1faI

通过回调的方式,就可以在读取文件A之后,紧接着读取文件B。

如果我们还想在文件B之后,继续读取文件C呢?这就需要继续嵌套回调:

fs.readFile(&#39;./A.txt&#39;, (err, data) => {//第一次回调
    if (err) {
        console.log(err.message)
        return
    }
    console.log(&#39;读取文件A:&#39; + data.toString())
    fs.readFile(&#39;./B.txt&#39;, (err, data) => {//第二次回调
        if (err) {
            console.log(err.message)
            return
        }
        console.log("读取文件B:" + data.toString())
        fs.readFile(&#39;./C.txt&#39;,(err,data)=>{//第三次回调
            ...
        })
    })
})
ログイン後にコピー

也就是说,如果我们想要依次执行多个异步操作,需要多层嵌套回调,这在层数较少时是行之有效的,但是当嵌套次数过多时,会出现一些问题。

回调的约定

实际上,fs.readFile中的回调函数的样式并非个例,而是JavaScript中的普遍约定。我们日后会自定义大量的回调函数,也需要遵守这种约定,形成良好的编码习惯。

约定是:

  • callback 的第一个参数是为 error 而保留的。一旦出现 error,callback(err) 就会被调用。
  • 第二个以及后面的参数用于接收异步操作的成功结果。此时 callback(null, result1, result2,...) 就会被调用。

基于以上约定,一个回调函数拥有错误处理和结果接收两个功能,例如fs.readFile(&#39;...&#39;,(err,data)=>{})的回调函数就遵循了这种约定。

五、回调地狱

如果我们不深究的话,基于回调的异步方法处理似乎是相当完美的处理方式。问题在于,如果我们有一个接一个 的异步行为,那么代码就会变成这样:

fs.readFile(&#39;./a.txt&#39;,(err,data)=>{
    if(err){
        console.log(err.message)
        return
    }
    //读取结果操作
    fs.readFile(&#39;./b.txt&#39;,(err,data)=>{
        if(err){
            console.log(err.message)
            return
        }
        //读取结果操作
        fs.readFile(&#39;./c.txt&#39;,(err,data)=>{
            if(err){
                console.log(err.message)
                return
            }
            //读取结果操作
            fs.readFile(&#39;./d.txt&#39;,(err,data)=>{
                if(err){
                    console.log(err.message)
                    return
                }
                ...
            })
        })
    })
})
ログイン後にコピー

以上代码的执行内容是:

  • 读取文件a.txt,如果没有发生错误的话;
  • 读取文件b.txt,如果没有发生错误的话;
  • 读取文件c.txt,如果没有发生错误的话;
  • 读取文件d.txt,…

随着调用的增加,代码嵌套层级越来越深,包含越来越多的条件语句,从而形成不断向右缩进的混乱代码,难以阅读和维护。

我们称这种不断向右增长(向右缩进)的现象为“回调地狱”或者“末日金字塔”!

fs.readFile(&#39;a.txt&#39;,(err,data)=>{
    fs.readFile(&#39;b.txt&#39;,(err,data)=>{
        fs.readFile(&#39;c.txt&#39;,(err,data)=>{
            fs.readFile(&#39;d.txt&#39;,(err,data)=>{
                fs.readFile(&#39;e.txt&#39;,(err,data)=>{
                    fs.readFile(&#39;f.txt&#39;,(err,data)=>{
                        fs.readFile(&#39;g.txt&#39;,(err,data)=>{
                            fs.readFile(&#39;h.txt&#39;,(err,data)=>{
                                ...
                                /*
								  通往地狱的大门
								  ===>
                                */
                            })
                        })
                    })
                })
            })
        })
    })
})
ログイン後にコピー

虽然以上代码看起来相当规整,但是这只是用于举例的理想场面,通常业务逻辑中会有大量的条件语句、数据处理操作等代码,从而打乱当前美好的秩序,让代码变的难以维护。

幸运的是,JavaScript为我们提供了多种解决途径,Promise就是其中的最优解。

【相关推荐:javascript视频教程web前端

以上がJavaScriptにおける非同期とコールバックの基本概念とコールバック地獄現象の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 Dec 17, 2023 pm 02:54 PM

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 はじめに: 技術の継続的な発展により、音声認識技術は人工知能の分野の重要な部分になりました。 WebSocket と JavaScript をベースとしたオンライン音声認識システムは、低遅延、リアルタイム、クロスプラットフォームという特徴があり、広く使用されるソリューションとなっています。この記事では、WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法を紹介します。

WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー WebSocket と JavaScript: リアルタイム監視システムを実装するための主要テクノロジー Dec 17, 2023 pm 05:30 PM

WebSocketとJavaScript:リアルタイム監視システムを実現するためのキーテクノロジー はじめに: インターネット技術の急速な発展に伴い、リアルタイム監視システムは様々な分野で広く利用されています。リアルタイム監視を実現するための重要なテクノロジーの 1 つは、WebSocket と JavaScript の組み合わせです。この記事では、リアルタイム監視システムにおける WebSocket と JavaScript のアプリケーションを紹介し、コード例を示し、その実装原理を詳しく説明します。 1.WebSocketテクノロジー

JavaScript と WebSocket を使用してリアルタイムのオンライン注文システムを実装する方法 JavaScript と WebSocket を使用してリアルタイムのオンライン注文システムを実装する方法 Dec 17, 2023 pm 12:09 PM

JavaScript と WebSocket を使用してリアルタイム オンライン注文システムを実装する方法の紹介: インターネットの普及とテクノロジーの進歩に伴い、ますます多くのレストランがオンライン注文サービスを提供し始めています。リアルタイムのオンライン注文システムを実装するには、JavaScript と WebSocket テクノロジを使用できます。 WebSocket は、TCP プロトコルをベースとした全二重通信プロトコルで、クライアントとサーバー間のリアルタイム双方向通信を実現します。リアルタイムオンラインオーダーシステムにおいて、ユーザーが料理を選択して注文するとき

WebSocketとJavaScriptを使ったオンライン予約システムの実装方法 WebSocketとJavaScriptを使ったオンライン予約システムの実装方法 Dec 17, 2023 am 09:39 AM

WebSocket と JavaScript を使用してオンライン予約システムを実装する方法 今日のデジタル時代では、ますます多くの企業やサービスがオンライン予約機能を提供する必要があります。効率的かつリアルタイムのオンライン予約システムを実装することが重要です。この記事では、WebSocket と JavaScript を使用してオンライン予約システムを実装する方法と、具体的なコード例を紹介します。 1. WebSocket とは何ですか? WebSocket は、単一の TCP 接続における全二重方式です。

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 Dec 17, 2023 pm 05:13 PM

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 はじめに: 今日、天気予報の精度は日常生活と意思決定にとって非常に重要です。テクノロジーの発展に伴い、リアルタイムで気象データを取得することで、より正確で信頼性の高い天気予報を提供できるようになりました。この記事では、JavaScript と WebSocket テクノロジを使用して効率的なリアルタイム天気予報システムを構築する方法を学びます。この記事では、具体的なコード例を通じて実装プロセスを説明します。私たちは

簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 簡単な JavaScript チュートリアル: HTTP ステータス コードを取得する方法 Jan 05, 2024 pm 06:08 PM

JavaScript チュートリアル: HTTP ステータス コードを取得する方法、特定のコード例が必要です 序文: Web 開発では、サーバーとのデータ対話が頻繁に発生します。サーバーと通信するとき、多くの場合、返された HTTP ステータス コードを取得して操作が成功したかどうかを判断し、さまざまなステータス コードに基づいて対応する処理を実行する必要があります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法を説明し、いくつかの実用的なコード例を示します。 XMLHttpRequestの使用

JavaScriptでinsertBeforeを使用する方法 JavaScriptでinsertBeforeを使用する方法 Nov 24, 2023 am 11:56 AM

使用法: JavaScript では、insertBefore() メソッドを使用して、DOM ツリーに新しいノードを挿入します。このメソッドには、挿入される新しいノードと参照ノード (つまり、新しいノードが挿入されるノード) の 2 つのパラメータが必要です。

JavaScript と WebSocket: 効率的なリアルタイム画像処理システムの構築 JavaScript と WebSocket: 効率的なリアルタイム画像処理システムの構築 Dec 17, 2023 am 08:41 AM

JavaScript は Web 開発で広く使用されているプログラミング言語であり、WebSocket はリアルタイム通信に使用されるネットワーク プロトコルです。 2 つの強力な機能を組み合わせることで、効率的なリアルタイム画像処理システムを構築できます。この記事では、JavaScript と WebSocket を使用してこのシステムを実装する方法と、具体的なコード例を紹介します。まず、リアルタイム画像処理システムの要件と目標を明確にする必要があります。リアルタイムの画像データを収集できるカメラ デバイスがあるとします。

See all articles