目次
1. はじめに
2. Promise
3. Promise 入門ガイド
四、模拟Promise

JavaScript の Promise の詳細な紹介

Mar 04, 2017 pm 03:30 PM
javascript

1. はじめに

JavaScript はシングルスレッドであり、一度に 1 つのタスクしか実行できません。タスクに時間がかかると、後続のタスクは待機する必要があります。では、このような問題を解決する方法はあるのでしょうか? (WebWorker は置いといて)、つまり、コードを非同期に実行させることです。これは何を意味しますか? たとえば、Ajax 非同期リクエストを行う場合、readyState の値が継続的に監視され、指定されたコールバック関数の実行が決定されます。

非同期実行には通常、コールバック関数、イベント リスニング、パブリッシュとサブスクライブの 3 つのタイプがあります。イベント リスニングとパブリッシュとサブスクライブは実際には似ていますが、後者の方が堅牢です。

コールバック関数と同様に、コールバック関数は非同期実行に適用される最も単純なプログラミングのアイデアです。以下の通り:

function async(item,callback){
    console.log(item);
    setTimeout(function(){
        callback(item+1);
    },1000);    
}
ログイン後にコピー

上記の例では、async 関数が実行されると印刷操作が完了し、1 秒後にコールバック関数が実行されます (ただし、必ずしも 1 秒である必要はありません。詳細については「setTimeout に関する事項」を参照してください)。

非同期の主な目的は、ノンブロッキングを処理し、パフォーマンスを向上させることです。次のように、操作に複数の非同期関数操作が必要な場合を想像してください:

async(1, function(item){
    async(item, function(item){
        async(item, function(item){
            console.log('To be continued..');
        });
    });
});
ログイン後にコピー

少し読みにくいですか?

別の例として、上記のコードをより堅牢にするために、例外キャッチを追加できます。非同期モードでは、例外処理がさまざまなコールバック関数に分散され、呼び出し時に try...catch を介して例外を処理できないため、効果的かつ明確に実行することが困難です。

ああ、どうすればいいですか?

ブンブンブン、ブンブンブン – 約束がここにあります。

ES6 Promise を使用して上記のコードを最適化すると、次のことが得られます:

function opration(item){
    var p = new Promise(function(resolve, reject){
        setTimeout(function(){
            resolve(item+1);
        },1000);
    });
    console.log(item);
    return p;
}
function failed(e){
    console.log(e);
}
Promise.resolve(1).then(opration).then(opration).then(opration).catch(failed);
ログイン後にコピー

Promise の使用 最適化されたコードには、コールバック関数をチェーン呼び出しに変換し、ネストの層を回避し、プログラムを変更するという明らかな利点があります。フローは明確である必要があり、1 つ以上のコールバック関数によってスローされたエラーは catch メソッドを通じて均一に処理される必要があります。

ああ、それはいいのですが、ES6 の Promise とは誰ですか?具体的な使用ルールは何ですか?一緒に調べてみましょう。

2. Promise

Promise は、従来のソリューション (コールバックやイベント) よりも合理的かつ強力な非同期プログラミングのソリューションです。これは最初にコミュニティによって提案および実装され、ES6 がそれを言語標準に組み込み、その使用法を統一し、Promise オブジェクトをネイティブに提供しました。

Promise オブジェクトには 3 つの状態しかありません:

1、 保留中: 非同期操作は完了していません。

2、が解決されました: 非同期操作が完了しました。

3. 拒否: 非同期操作が失敗しました。

また、これら 3 つの状態には 2 つの変更モードしかなく、一度状態が変更されると、再度変更されることはありません:

1、保留中から解決済みへの非同期操作

2、からの非同期操作。拒否されるまで保留中です。

そうですね、これは ES6 仕様に属しているので、Chrome を介して Promise を直接出力して、これを見ることができます:

まあ、Promise がコンストラクター、OK、渡されました。これを使用すると、独自の Promise オブジェクトをインスタンス化し、それを使用できます。

3. Promise 入門ガイド

Promise はコンストラクターなので、最初に新しいものを見てみましょう。次のように:

var p = new Promise();
ログイン後にコピー

して上記のコードを実行すると、Chrome のスクリーンショットは次のようになります:

エラーが報告されるのはなぜですか?

ところで、Promise コンストラクターにはパラメーターとして関数が必要で、パラメーターとしての関数には 2 つのパラメーターがあり、非同期操作が保留中から解決済みに変更されるときに関数を提供するために使用されます。 2 番目のパラメータは、非同期操作が保留中から拒否されたときに呼び出すために使用されます。

たとえば、匿名関数の最初のパラメータにはresolveという名前を付け、2番目のパラメータにはrejectという名前を付けました。デモは次のとおりです:

var p = new Promise(function(resolve, reject){
    console.log('new一个Promise对象');
    setTimeout(function(){
        resolve('Monkey');
    },1000);
});
ログイン後にコピー

と上記のコードを実行します。 Chrome のスクリーンショットは次のとおりです:

特別な注意事項: 匿名関数がコンストラクター Promise のパラメーターとして渡されるとき、 new では、上に示したように、匿名関数がすでに実行されています。

上記のコードでは、匿名関数で setTimeout タイマーを使用し、1 秒後にresolveを呼び出していますが、なぜ未定義またはエラーが報告されないのでしょうか? !

これが約束の力です。このため、非同期操作をエレガントなチェーン呼び出しに書き直すことができます。なんと呼びますか?

「Promise の概要」セクションで、Chrome 経由で Promise を印刷し、赤い線のボックス内の領域を使用したことを覚えていますか?このうち、Promise プロトタイプには then メソッド (Promise.prototype.then) があり、これを介せば十分です。以下の通り:

p.then(function(value){
    console.log(value);
});
ログイン後にコピー

このうち、then メソッドはパラメータとして 2 つの匿名関数を持ち、これは Promise のsolve パラメータとreject パラメータに対応します。コードを実行すると、結果は次のようになります:

好了,当then执行完后,如果我们想继续在其之后看,使用then方法链式调用,有两种情况,一种是直接返回非Promise对象的结果;另一种是返回Promise对象的结果。

1、返回非Promise对象的结果:紧跟着的then方法,resolve立刻执行。并可使用前一个then方法返回的结果。如下:

p.then(function(value){
    console.log(value);
    //返回非Promise对象,如我的对象
    return {
        name: 'Dorie',
        age: 18
    };
}).then(function(obj){
    console.log(obj.name);
});
ログイン後にコピー

执行上述完整代码,chrome截图如下:

2、返回Promise对象的结果:紧跟着的then方法,与new Promise后的then方法一样,需等待前面的异步执行完后,resolve方可被执行。如下:

p.then(function(value){
    var p = new Promise(function(resolve, reject){
        setTimeout(function(){
            var message = value + ' V Dorie'
            resolve(message);
        },1000);
    });
    console.log(value);
    //返回一个Promise对象
    return p;
}).then(function(value){
    console.log(value);
});
ログイン後にコピー

执行上述完整代码,chrome截图如下:

那么,当创建、执行Promise方法中有异常报错,如何捕获呢?

Promise.prototype.catch原型方法,就是为其而设定的。它具有冒泡的特性,比如当创建Promise实例时,就出错了,错误消息就会通过链式调用的这条链,一直追溯到catch方法,如果找到尽头都没有,就报错,并且再找到catch之前的所有then方法都不能执行了。Demo如下(代码太长,请自行展开):

<!DOCTYPE html>
    <head>
        <title>test</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    </head>
    <body>
        <script>
            var p = new Promise(function(resolve, reject){
                //M未定义
                console.log(M);
                setTimeout(function(){
                    resolve(&#39;Monkey&#39;);
                },1000);
            });
            p.then(function(value){
                var p = new Promise(function(resolve, reject){
                    setTimeout(function(){
                        var message = value + &#39; V Dorie&#39;
                        resolve(message);
                    },1000);
                });
                console.log(value);
                //返回一个Promise对象
                return p;
            }).then(function(value){
                console.log(value);
                return &#39;next is catch&#39;;
            }).catch(function(e){
                console.log(e);
            }).then(function(value){
                console.log(&#39;execute,but value is &#39; + value);
            });
        </script>
    </body>
</html>
ログイン後にコピー

执行上述代码,chrome截图如下:

好了,到这里,我们已经了解了最常用的Promise.prototype.then和Promise.prototype.catch这两个原型方法。另外,像Promise构造函数还有属于自身的方法,如all、rece、resolve、reject等,详情请点击这里(here)。

通过一路上对Promise的讲述,我们也有了一定的认识,其实Promise并没有想象中的那么难以理解嘛。懂得Promise概念后,其实我们自己也可以实现一个简易版的Promise。下面就一同尝试实现一个呗。

四、模拟Promise

假设:有三个异步操作方法f1,f2,f3,且f2依赖于f1,f3依赖于f2。如果,我们采用ES6中Promise链式调用的思想,我们可以将程序编写成这样:

f1().then(f2).then(f3);
ログイン後にコピー

那么,通过上面这一系列链式调用,怎样才能达到与ES6中Promise相似的功能呢?

初步想法:首先将上述链式调用的f2、f3保存到f1中,当f1中的异步执行完后,再调用执行f2,并将f1中的f3保存到f2中,最后,等f2中的异步执行完毕后,调用执行f3。详细构思图,如下:

从上图可知,由于f1、f2 、f3是可变得,所以存储数组队列thens,可放入,我们即将创建的模拟Promise构造函数中。具体实现代码如下:

//模拟Promise
function Promise(){
    this.thens = [];
};
Promise.prototype = {
    constructor: Promise,
    then: function(callback){
        this.thens.push(callback);
        return this;        
    }
};
ログイン後にコピー

并且,需要一个Promise.prototype.resolve原型方法,来实现:当f1异步执行完后,执行紧接着f1后then中的f2方法,并将后续then中方法,嫁接到f2中,如f3。具体实现代码如下:

//模拟Promise,增加resolve原型方法
function Promise(){
    this.thens = [];
};
Promise.prototype = {
    constructor: Promise,
    then: function(callback){
        this.thens.push(callback);
        return this;        
    },
    resolve: function(){
        var t = this.thens.shift(), 
            p;
        if(t){
            p = t.apply(null,arguments);
            if(p instanceof Promise){
                p.thens = this.thens;
            }
        }
    }
};
ログイン後にコピー

测试代码(代码太长,自行打开并运行)。

function f1() {
    var promise = new Promise();
    setTimeout(function () {

        console.log(1);
        promise.resolve();
    }, 1500)

    return promise;
}

function f2() {
    var promise = new Promise();
    setTimeout(function () {
        console.log(2);
        promise.resolve();
    }, 1500);
    return promise;
}

function f3() {
    var promise = new Promise();
    setTimeout(function () {

        console.log(3);
        promise.resolve();
    }, 1500)

    return promise;
}
f1().then(f2).then(f3);
ログイン後にコピー

仔细品味,上述实现的Promise.prototype.resolve方法还不够完美,因为它只能够满足于f1、f2、f3等方法都是使用模拟的Promise异步执行的情况。而,当其中有不是返回的Promise对象的呢,而是返回一个数字,亦或是什么也不返回,该怎么办?所以,针对以上提出的种种可能,再次改进resolve。改善代码如下:

//模拟Promise,改善resolve原型方法
var Promise = function () {
    this.thens = [];
};
Promise.prototype = {
    constructor: Promise,
    then: function(callback){
        this.thens.push(callback);
        return this;        
    },
    resolve: function () {
        var t,p;
        t = this.thens.shift();
        t && (p = t.apply(null, arguments));
        while(t && !(p instanceof Promise)){
            t = this.thens.shift();
            t && (p = t.call(null, p));    
        }
        if(this.thens.length){
            p.thens = this.thens;
        };
    }
}
ログイン後にコピー

测试代码(代码太长,自行打开并运行)。

function f1() {
    var promise = new Promise();
    setTimeout(function () {

        console.log(1);
        promise.resolve();
    }, 1500)

    return promise;
}

function f2() {
    var promise = new Promise();
    setTimeout(function () {
        console.log(2);
        promise.resolve();
    }, 1500);
    return promise;
}

function f3() {
    var promise = new Promise();
    setTimeout(function () {

        console.log(3);
        promise.resolve();
    }, 1500)

    return promise;
}

function f4() {
    console.log(4);
    return 11;
}

function f5(x) {
    console.log(x+1);
}

function f6() {
    var promise = new Promise();
    setTimeout(function () {

        console.log(6);
        promise.resolve();
    }, 1500)

    return promise;
}

function f7() {
    console.log(7);
}

var that = f1().then(f2).then(f3).then(f4).then(f5).then(f6).then(f7);
ログイン後にコピー

好了,初步模拟的Promise就OK啦。

吼吼,对于Promise,我们这一路走来,发现原来也不过如此呢。

 以上就是详细介绍JavaScript 中的 Promise的内容,更多相关内容请关注PHP中文网(www.php.cn)!

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、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衣類リムーバー

AI Hentai Generator

AI Hentai Generator

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でinsertBeforeを使用する方法 JavaScriptでinsertBeforeを使用する方法 Nov 24, 2023 am 11:56 AM

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

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

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

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

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

See all articles