この記事では、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 サイトの他の関連記事を参照してください。