Promise オブジェクトの詳細な分析 (例付き)

不言
リリース: 2018-11-23 14:49:00
転載
2192 人が閲覧しました

この記事では、Promise オブジェクトの詳細な分析を (例とともに) 紹介します。必要な方は参考にしていただければ幸いです。

jsのAsynchronousは当初コールバック関数を使って実装されていたため、asynchronousを入れ子にするとコールバック地獄が発生してコードが読みづらくなったり、メンテナンスが難しくなったりします その後es6が登場してpromiseを使うことでコールバックの問題が解決します。地獄。ここで、Promise を実装するためのコードを自分たちで記述します。これにより、Promise の動作メカニズムを深く理解し、将来的に Promise をより快適に使用できるようになります。始める前に、Promise の公式 Web サイトの Promise/A

まずは Promise の使用法を見てみましょう

new Promise((resolve,reject)=>{
  resolve(1);
  reject(11);
}).then(res=>{
  console.log(res);
  setTimeout(()=>{
    return new Promise((resolve,reject)=>{
        resolve(2)
    }) 
  },1000)
}).then(res2=>{
  console.log(res2);
});
ログイン後にコピー

コンソール印刷
1
...1s後で
2

最初に上記のコードを分析して、いくつかの質問をしてみましょう
1. 最初の段落には解決と拒否の両方がありますが、出力されるのは 1 つだけです。
2.res はどのようにして、resolve の値を取得するのでしょうか?
3.Promise はどのようにしてチェーン呼び出しを実現しますか?

ステート マシン

Promise にはステート マシンの概念がある理由について最初に説明します。Promise の状態は一方向に変化し、3 つの状態があるからです。 : pending、fullfilled、rejected。これら 3 つの状態は、pending->fullfilled または pending->rejected の形式のみになります。つまり、fullfilled が実行された後は、rejected は実行されません。これで上記の最初の質問が説明されます。

特定の実装の完全なコードを見てみましょう

const PENDING = 'PENDING';
const FULLFILLED = 'FULLFILLED';
const REJECTED = 'REJECTED';    
class Promise{
    constructor(fn){
       this.status = PENDING;//状态
        this.data = undefined;//返回值
        this.defercb = [];//回调函数数组
        //执行promise的参数函数,并把resolve和reject的this绑定到promise的this
        fn(this.resolve.bind(this),this.reject.bind(this));
    }
    resolve(value){
        if(this.status === PENDING){
            //只能pending=>fullfied
            this.status = FULLFILLED;
            this.data = value;
            this.defercb.map(item=>item.onFullFilled());
        }
    }
    reject(value){
        if(this.status === PENDING){
            //只能pending=>rejected
            this.status = REJECTED;
            this.data = value;
            this.defercb.map(item=>item.onRejected());
        }
    }
    then(resolveThen,rejectThen){
       //如果没有resolveThen方法,保证值可以穿透到下一个then里有resolveThen的方法中
        resolveThen = typeof resolveThen === 'function' ? resolveThen : function(v) {return v};
        rejectThen = typeof rejectThen === 'function' ? rejectThen : function(r) {return r};
        //返回的都是promise对象,这样就可以保证链式调用了
        switch(this.status){
            case PENDING:
            return new Promise((resolve,reject)=>{
                const onFullFilled = () => {
                    const result = resolveThen(this.data);//这里调用外部then的resolveThen方法,将值传回去
                    //如果返回值是promise对象,执行then方法,取它的结果作为新的promise实例的结果,因为this.data会重新赋值
                    result instanceof Promise && result.then(resolve,reject);
                }
                const onRejected = ()=>{
                    const result = rejectThen(this.data);
                    result instanceof Promise && result.then(resolve,reject);
                }
                this.defercb.push({onFullFilled,onRejected});
            });
            break;
            case FULLFILLED:
               return new Promise((resolve,reject)=>{
                     const result = resolveThen(this.data);
                     result instanceof Promise && result.then(resolve,reject);
                     resolve(result);
               })
            break;
            case REJECTED:
               return new Promise((resolve,reject)=>{
                   const result = rejectThen(this.data);
                   result instanceof Promise && result.then(resolve,reject);
                   reject(result)
               })   
            break;
        }
    }
}
ログイン後にコピー

次の例を実行します

new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(1);
    }, 1000);
}).then((res2) => {
    console.log(res2);
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(2);
        }, 1000);
    });
}).then((res3) => {
    console.log(res3);
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(3);
        }, 1000);
    });
}).then((res4) => {
    console.log(res4);
});
ログイン後にコピー

コンソール印刷
...1 秒後
1
...1秒後
2
...1秒後
3
上記の実装には問題がないことを意味します
しかし、別の問題があります。たとえば、次のコード

new Promise((resolve) => {
    resolve();
})
.then(() => {
    console.log('1');
})
.then(() => {
    console.log('2');
});
console.log('3');
ログイン後にコピー

を実行すると、期待どおりに 3,1,2 が出力されず、1,2,3 が出力されます。これは、Promise がメインスレッドにあるためです。この問題を解決するには、タスク キューに settimeout を追加します。ただし、これは実行シーケンスをよりよく理解できるようにするためのものです。ただし、実際には、Promise はマイクロ タスクに属し、settimeout はマクロに属します。

タスクはまだ異なります。

以上がPromise オブジェクトの詳細な分析 (例付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:segmentfault.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート