web-dev-qa-db-ja.com

Edgeでfinally()をサポートするためにポリフィルを追加するにはどうすればよいですか?

私はaxiosライブラリを使用し、then()、catch()、finally()を使用しています。 Chromeで完全に動作します。ただし、finally()メソッドはMS Edgeでは機能しません。ポリフィルやシムを使って調査したところ、道に迷いました。私はウェブパックやトランスパイルを使用しておらず、追加する予定もありません。これをシンプルに保つ必要があります。ポリフィルを追加して、finally()がEdgeで機能することを確認するにはどうすればよいですか?ありがとう!

8
Craig

これは、以下に詳述する動作に加えて、thenableの伝播 species を処理する必要があります。

_Promise.prototype.finally = Promise.prototype.finally || {
  finally (fn) {
    const onFinally = value => Promise.resolve(fn()).then(() => value);
    return this.then(
      result => onFinally(result),
      reason => onFinally(Promise.reject(reason))
    );
  }
}.finally;
_

この実装は finally() の文書化された動作に基づいており、仕様に準拠している then() に依存します。

  • finallyコールバックは引数を受け取りません。これは、promiseが実行されたか拒否されたかを判断する信頼できる手段がないためです。このユースケースは、拒否の理由やフルフィルメントの値を気にしない場合に使用するため、提供する必要はありません。

  • Promise.resolve(2).then(() => {}, () => {})undefinedで解決される)とは異なり、Promise.resolve(2).finally(() => {})は_2_で解決されます。

  • 同様に、Promise.reject(3).then(() => {}, () => {})undefinedで満たされる)とは異なり、Promise.reject(3).finally(() => {})は_3_で拒否されます。

注:throwコールバックのfinally(または拒否されたpromiseを返す)は、 throw()の呼び出し時に指定された拒否理由。

そしてもちろん、同等の動作のデモ:

_const logger = (label, start = Date.now()) => (...values) => {
  console.log(label, ...values, `after ${Date.now() - start}ms`);
};

const delay = (value, ms) => new Promise(resolve => {
  setTimeout(resolve, ms, value);
});

// run test on native implementation
test('native');

// force Promise to use the polyfill implementation
Promise.prototype.finally = /* Promise.prototype.finally || */ {
  finally (fn) {
    const onFinally = value => Promise.resolve(fn()).then(() => value);
    return this.then(
      result => onFinally(result),
      reason => onFinally(Promise.reject(reason))
    );
  }
}.finally;

// run test on polyfill implementation
test('polyfill');

function test (impl) {
  const log = ordinal => state => logger(`${ordinal} ${impl} ${state}`);
  const first = log('first');

  // test propagation of resolved value
  delay(2, 1000)
    .finally(first('settled'))
    .then(first('fulfilled'), first('rejected'));

  const second = log('second');

  // test propagation of rejected value
  delay(Promise.reject(3), 2000)
    .finally(second('settled'))
    .then(second('fulfilled'), second('rejected'));

  const third = log('third');

  // test adoption of resolved promise
  delay(4, 3000)
    .finally(third('settled'))
    .finally(() => delay(6, 500))
    .then(third('fulfilled'), third('rejected'));

  const fourth = log('fourth');

  // test adoption of rejected promise
  delay(5, 4000)
    .finally(fourth('settled'))
    .finally(() => delay(Promise.reject(7), 500))
    .then(fourth('fulfilled'), fourth('rejected'));
}_
_.as-console-wrapper{max-height:100%!important}_

@ Bergi にこの回答についてのご意見をお寄せいただきありがとうございます。 彼の実装 を参照して、この投稿が役に立ったと思われる場合は、それも賛成投票してください。

9
Patrick Roberts