検索
ホームページウェブフロントエンドjsチュートリアルJavaScript の非同期とコールバックの基本概念を要約して共有します。

本篇文章给大家带来了关于javascript的相关知识,其中主要整理了异步与回调的基本概念的相关问题,同步,一般指按照预定的顺序依次执行任务,只有当上一个任务完成后,才开始执行下一个任务,异步,与同步相对应,异步指的是让CPU暂时搁置当前任务,先处理下一个任务,当收到上个任务的回调通知后,再返回上个任务继续执行,下面一起来看一下,希望对大家有帮助。

JavaScript の非同期とコールバックの基本概念を要約して共有します。

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

一、前言

在学习本文内容之前,我们必须要先了解异步的概念,首先要强调的是异步和并行有着本质的区别

  • 并行,一般指并行计算,是说同一时刻有多条指令同时被执行,这些指令可能执行于同一CPU的多核上,或者多个CPU上,或者多个物理主机甚至多个网络中。

  • 同步,一般指按照预定的顺序依次执行任务,只有当上一个任务完成后,才开始执行下一个任务。

  • 异步,与同步相对应,异步指的是让CPU暂时搁置当前任务,先处理下一个任务,当收到上个任务的回调通知后,再返回上个任务继续执行,整个过程无需第二个线程参与

也许用图片的方式解释并行、同步和异步更为直观,假设现在有A、B两个任务需要处理,使用并行、同步和异步的处理方式会分别采用如下图所示的执行方式:

JavaScript の非同期とコールバックの基本概念を要約して共有します。

二、异步函数

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')
        })
    })}

函数copyFile首先从参数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 finished
PS E:\Code\Node\demos\03-callback> node .\index.js
错误:ENOENT: no such file or directory, open 'E:\Code\Node\demos\03-callback\to.txt'Copy finished

即使./to.txt存在,也无法读取其中复制的内容。

造成这种现象的原因是:copyFile(...)是异步执行的,程序执行到copyFile(...)函数后,并不会等待其复制完毕,而是直接向下执行,从而导致出现文件./to.txt不存在的错误,或者文件内容为空错误(如果提前创建文件)。

三、回调函数

异步函数的具体执行结束的时间是不能确定的,例如readFile(from,to)函数的执行结束时间大概率取决于文件from的大小。

那么,问题在于我们如何才能准确的定位copyFile执行结束,从而读取to文件中的内容呢?

这就需要使用回调函数,我们可以修改copyFile函数如下:

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('Copy finished')
            callback()//当复制操作完成后调用回调函数
        })
    })}

这样,我们如果需要在文件复制完成后,立即执行一些操作,就可以把这些操作写入回调函数中:

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('Copy finished')
            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文件,那么以上代码就可以直接运行:

PS E:\Code\Node\demos\03-callback> node .\index.js
Copy finished
加入社区“仙宗”,和我一起修仙吧
社区地址:http://t.csdn.cn/EKf1h

这种编程方式被称为“基于回调”的异步编程风格,异步执行的函数应当提供一个回调参数用于在任务结束后调用。

这种风格在JavaScript编程中普遍存在,例如文件读取函数fs.readFilefs.writeFile都是异步函数。

四、回调的回调

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

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

代码实现:

fs.readFile('./A.txt', (err, data) => {
    if (err) {
        console.log(err.message)
        return
    }
    console.log('读取文件A:' + data.toString())
    fs.readFile('./B.txt', (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('./A.txt', (err, data) => {//第一次回调
    if (err) {
        console.log(err.message)
        return
    }
    console.log('读取文件A:' + data.toString())
    fs.readFile('./B.txt', (err, data) => {//第二次回调
        if (err) {
            console.log(err.message)
            return
        }
        console.log("读取文件B:" + data.toString())
        fs.readFile('./C.txt',(err,data)=>{//第三次回调
            ...
        })
    })})

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

回调的约定

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

约定是:

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

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

五、回调地狱

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

fs.readFile('./a.txt',(err,data)=>{
    if(err){
        console.log(err.message)
        return
    }
    //读取结果操作
    fs.readFile('./b.txt',(err,data)=>{
        if(err){
            console.log(err.message)
            return
        }
        //读取结果操作
        fs.readFile('./c.txt',(err,data)=>{
            if(err){
                console.log(err.message)
                return
            }
            //读取结果操作
            fs.readFile('./d.txt',(err,data)=>{
                if(err){
                    console.log(err.message)
                    return
                }
                ...
            })
        })
    })})

以上代码的执行内容是:

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

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

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

fs.readFile('a.txt',(err,data)=>{
    fs.readFile('b.txt',(err,data)=>{
        fs.readFile('c.txt',(err,data)=>{
            fs.readFile('d.txt',(err,data)=>{
                fs.readFile('e.txt',(err,data)=>{
                    fs.readFile('f.txt',(err,data)=>{
                        fs.readFile('g.txt',(err,data)=>{
                            fs.readFile('h.txt',(err,data)=>{
                                ...
                                /*
								  通往地狱的大门
								  ===>
                                */
                            })
                        })
                    })
                })
            })
        })
    })})

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

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

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

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

声明
この記事はCSDNで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。
CおよびJavaScript:接続が説明しましたCおよびJavaScript:接続が説明しましたApr 23, 2025 am 12:07 AM

CおよびJavaScriptは、WebAssemblyを介して相互運用性を実現します。 1)CコードはWebAssemblyモジュールにコンパイルされ、JavaScript環境に導入され、コンピューティングパワーが強化されます。 2)ゲーム開発では、Cは物理エンジンとグラフィックスレンダリングを処理し、JavaScriptはゲームロジックとユーザーインターフェイスを担当します。

Webサイトからアプリまで:JavaScriptの多様なアプリケーションWebサイトからアプリまで:JavaScriptの多様なアプリケーションApr 22, 2025 am 12:02 AM

JavaScriptは、Webサイト、モバイルアプリケーション、デスクトップアプリケーション、サーバー側のプログラミングで広く使用されています。 1)Webサイト開発では、JavaScriptはHTMLおよびCSSと一緒にDOMを運用して、JQueryやReactなどのフレームワークをサポートします。 2)ReactNativeおよびIonicを通じて、JavaScriptはクロスプラットフォームモバイルアプリケーションを開発するために使用されます。 3)電子フレームワークにより、JavaScriptはデスクトップアプリケーションを構築できます。 4)node.jsを使用すると、JavaScriptがサーバー側で実行され、高い並行リクエストをサポートします。

Python vs. JavaScript:ユースケースとアプリケーションと比較されますPython vs. JavaScript:ユースケースとアプリケーションと比較されますApr 21, 2025 am 12:01 AM

Pythonはデータサイエンスと自動化により適していますが、JavaScriptはフロントエンドとフルスタックの開発により適しています。 1. Pythonは、データ処理とモデリングのためにNumpyやPandasなどのライブラリを使用して、データサイエンスと機械学習でうまく機能します。 2。Pythonは、自動化とスクリプトにおいて簡潔で効率的です。 3. JavaScriptはフロントエンド開発に不可欠であり、動的なWebページと単一ページアプリケーションの構築に使用されます。 4. JavaScriptは、node.jsを通じてバックエンド開発において役割を果たし、フルスタック開発をサポートします。

JavaScript通訳者とコンパイラにおけるC/Cの役割JavaScript通訳者とコンパイラにおけるC/Cの役割Apr 20, 2025 am 12:01 AM

CとCは、主に通訳者とJITコンパイラを実装するために使用されるJavaScriptエンジンで重要な役割を果たします。 1)cは、JavaScriptソースコードを解析し、抽象的な構文ツリーを生成するために使用されます。 2)Cは、Bytecodeの生成と実行を担当します。 3)Cは、JITコンパイラを実装し、実行時にホットスポットコードを最適化およびコンパイルし、JavaScriptの実行効率を大幅に改善します。

JavaScript in Action:実際の例とプロジェクトJavaScript in Action:実際の例とプロジェクトApr 19, 2025 am 12:13 AM

現実世界でのJavaScriptのアプリケーションには、フロントエンドとバックエンドの開発が含まれます。 1)DOM操作とイベント処理を含むTODOリストアプリケーションを構築して、フロントエンドアプリケーションを表示します。 2)node.jsを介してRestfulapiを構築し、バックエンドアプリケーションをデモンストレーションします。

JavaScriptとWeb:コア機能とユースケースJavaScriptとWeb:コア機能とユースケースApr 18, 2025 am 12:19 AM

Web開発におけるJavaScriptの主な用途には、クライアントの相互作用、フォーム検証、非同期通信が含まれます。 1)DOM操作による動的なコンテンツの更新とユーザーインタラクション。 2)ユーザーエクスペリエンスを改善するためにデータを提出する前に、クライアントの検証が実行されます。 3)サーバーとのリフレッシュレス通信は、AJAXテクノロジーを通じて達成されます。

JavaScriptエンジンの理解:実装の詳細JavaScriptエンジンの理解:実装の詳細Apr 17, 2025 am 12:05 AM

JavaScriptエンジンが内部的にどのように機能するかを理解することは、開発者にとってより効率的なコードの作成とパフォーマンスのボトルネックと最適化戦略の理解に役立つためです。 1)エンジンのワークフローには、3つの段階が含まれます。解析、コンパイル、実行。 2)実行プロセス中、エンジンはインラインキャッシュや非表示クラスなどの動的最適化を実行します。 3)ベストプラクティスには、グローバル変数の避け、ループの最適化、constとletsの使用、閉鎖の過度の使用の回避が含まれます。

Python vs. JavaScript:学習曲線と使いやすさPython vs. JavaScript:学習曲線と使いやすさApr 16, 2025 am 12:12 AM

Pythonは、スムーズな学習曲線と簡潔な構文を備えた初心者により適しています。 JavaScriptは、急な学習曲線と柔軟な構文を備えたフロントエンド開発に適しています。 1。Python構文は直感的で、データサイエンスやバックエンド開発に適しています。 2。JavaScriptは柔軟で、フロントエンドおよびサーバー側のプログラミングで広く使用されています。

See all articles

ホット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 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

PhpStorm Mac バージョン

PhpStorm Mac バージョン

最新(2018.2.1)のプロフェッショナル向けPHP統合開発ツール

MantisBT

MantisBT

Mantis は、製品の欠陥追跡を支援するために設計された、導入が簡単な Web ベースの欠陥追跡ツールです。 PHP、MySQL、Web サーバーが必要です。デモおよびホスティング サービスをチェックしてください。

SublimeText3 Mac版

SublimeText3 Mac版

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

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

WebStorm Mac版

WebStorm Mac版

便利なJavaScript開発ツール