JavaScript非同期プログラミングPromiseモードの6つの特性

3968 ワード

正式に紹介する前に、Javascript Promiseの様子を見たいです。

var p = new Promise(function(resolve, reject) {
  resolve("hello world");
});

p.then(function(str) {
  alert(str);
});
1.then()はForked Promiseに戻ります。
次の二つのコードは何の違いがありますか?

// Exhibit A
var p = new Promise(/*...*/);
p.then(func1);
p.then(func2);

// Exhibit B
var p = new Promise(/*...*/);
p.then(func1)
.then(func2);
上記の2つのコードが同じであれば、Promisesは1次元のコールバック関数配列にすぎない。しかし、実はそうではありません。各then()呼び出しはforked promiseに戻ります。そのため、ExhibitAでは、func 1()が例外を出すと、func 2()が正常に呼び出されます。
ExhibitBでは、func 1()がエラーを出すと、fun 2()は呼び出されなくなります。最初の呼び出しが新しいpromiseに戻りますので、これはfunc 1()で拒否されます。結果としてfunc 2()がスキップされます。
まとめ:promisesはforkされて複数の経路になります。複雑なフローチャートのようです。
2.Callbackは結果を伝えるべきです。
下のコードを実行すると警告がありますか?

var p = new Promise(function(resolve, reject) {
  resolve("hello world");
});

p.then(function(str) {})
.then(function(str) {
  alert(str);
});
第二のthen()のalertは何も表示されていません。これはプロミスの文脈において,その結果の変化がコールバック関数ではないからである。promiseは、あなたのコールバック関数が同じ結果を返すか、または置換結果を返して次のコールバック関数に伝達されることを期待しています。
同様に、adpaterを使用して結果を変化させると、次のようになる。

var feetToMetres = function(ft) { return ft*12*0.0254 };

var p = new Promise(/*...*/);

p.then(feetToMetres)
.then(function(metres) {
  alert(metres);
});
。上の層からの異常のみが捕捉される。
この二つのコードの違いは何ですか?

// Exhibit A
new Promise(function(resolve, reject) {
  resolve("hello world");
})
.then(
  function(str) {
    throw new Error("uh oh");
  },
  undefined
)
.then(
  undefined,
  function(error) {
    alert(error);
  }
);
 

// Exhibit B
new Promise(function(resolve, reject) {
  resolve("hello world");
})
.then(
  function(str) {
    throw new Error("uh oh");
  },
  function(error) {
    alert(error);
  }
);

は、第1のセグメントコードにおいて、第1のthen()における異常が投げ出され、第2のthen()によって捕捉され、その後、「uh oh」警告がトリガされる。これは前の段階だけに従う異常を捉える。
第二のセグメントコードでは、コールバック関数とエラーコール関数は同じレベルであり、例外がコールバックにおいてドロップされると、捕捉されないことを意味する。実際には、第二段コードのエラーリカバリーは、プロミセが拒否状態またはプロミス自体にエラーが発生した場合のみスローされます。
4.エラーは回復されます。
エラーリカバリー関数では、エラーを再投げしないと、promiseはエラーから回復したと仮定して、解決された状態に反転します。次の例では、「i'm saved」が表示されます。これは最初のthen()におけるエラーリカバリーが異常を再投げしていないためです。

var p = new Promise(function(resolve, reject) {
  reject(new Error("pebkac"));
});

p.then(
  undefined,
  function(error) { }
)
.then(
  function(str) {
    alert("I am saved!");
  },
  function(error) {
    alert("Bad computer!");
  }
);
Promiseは玉ねぎの上の階層と見なされてもよい。各then()は、もう一つの階層を玉ねぎに追加します。各階層は処理された活動を表しています。階層が終わると、結果は修復されたと考えられ、次の階層のために準備されています。
5.Promisesを一時停止することができます。
もう一つのthen()方法で実行する準備ができていますので、他の方法を一時停止できないという意味ではありません。現在のプロミスを一時停止するために、または他のプロミスを完成させるために、簡単にthenに別のプロミスに戻ります。

var p = new Promise(/*...*/);

p.then(function(str) {
  if(!loggedIn) {
    return new Promise(/*...*/);
  }
})
.then(function(str) {
  alert("Done.");
})
は前のコードの中で、新しいプロミスが解析されてからプロンプトが現れます。これは、既存の非同期コード経路において、より多くの依存性を導入する便利な方法である。例えば、ユーザsessionがtimeoutされていることを発見し、前のコードパスを続ける前に第二のログインを初期化することを望むかもしれない。
6.Resoloved Promisesはすぐには実行されません。
下のコードを実行するとヒントボックスがもらえますか?

function runme() {
  var i = 0;

  new Promise(function(resolve) {
    resolve();
  })
  .then(function() {
    i += 2;
  });
  alert(i);
}
promiseはすぐに解析されてから、then()メソッドはすぐに実行されますので、ヒント2が出ると思います。しかし、promise定義は、すべての呼び出しが強制的に非同期されることを要求しています。したがって、ヒントは変更される前に生成されます。