「労働者が自分の仕事をうまくやりたいなら、まず自分の道具を研ぎ澄まさなければなりません。」 - 孔子、「論語。陸霊公」
表紙 > プログラミング > 安全な割り当て

安全な割り当て

2024 年 11 月 5 日に公開
ブラウズ:510

Safe Assignment

今日は、JavaScript における安全な代入演算子 (?=) の新しい提案についてかなり話題になりました。私は JavaScript が時間の経過とともに改善されてきたことを気に入っていますが、これは最近いくつかのケースで遭遇する問題でもあります。関数として簡単な実装例を作成する必要がありますね?

この提案をまだ読んでいない場合のために、提案内容は次のとおりです:

const [error, value] ?= maybeThrows();

新しい ?= 演算子は、try/catch ブロック内の代入の右側を呼び出して配列を返すのと同じになります。代入内で何かがスローされた場合、返される配列の最初の値はエラーとなり、何もスローされなかった場合、2 番目の値は代入の結果になります。

よくあるトライ/キャッチの煩わしさ

私は、代入ブロックや try/catch ブロックの周りで非常に醜いコードに頻繁に遭遇します。このようなもの:

let errorMsg;

try {
  maybeThrow();
} catch (e) {
  errorMsg = "An error message";
}

try/catch ブロックの外側で errorMsg にアクセスするには、const を使用するか、ブロックの外側で定義する必要があります。

非同期の実装

ここでの最も簡単なケースは、非同期関数を処理することです。元気づけることができました
いくつかのテストケースと tryCatch という関数をすぐに実行できます:

function tryCatch(fn, ...args) {
  try {
    return [undefined, fn.apply(null, args)]
  } catch (e) {
    return [e, undefined];
  }
}

function throws() {
  throw new Error("It threw");
}

// returns a sum
// prints [ undefined, 2 ]
console.log(tryCatch(Math.sqrt, 4));

// returns an error
// prints [ Error: 'It threw', undefined ]
console.log(tryCatch(throws));

tryCatch は、try/catch ブロックでラップされた指定された引数を使用して関数を呼び出します。関数内で何もスローされない場合は適切に [未定義、結果] を返し、何かがスローされる場合は [エラー、未定義] を返します。

呼び出す関数がまだない場合は、tryCatch で匿名関数を使用することもできることに注意してください。

console.log(tryCatch(() => {
  throw new Error("It threw");
}));

非同期関数の処理

非同期関数は少し複雑になります。私が最初に考えていたアイデアの 1 つは、
と書くことでした。 完全に非同期のバージョンは、おそらく asyncTryCatch と呼ばれるものですが、その課題はどこにありますか。これは全く無意味な探索です!以下は、非同期関数と非同期関数の両方で動作する tryCatch の実装です:

function tryCatch(fn, ...args) {
  try {
    const result = fn.apply(null, args);

    if (result.then) {
      return new Promise(resolve => {
          result
            .then(v => resolve([undefined, v]))
            .catch(e => resolve([e, undefined]))  
      }); 
    }

    return [undefined, result];
  } catch (e) {
    return [e, undefined];
  }
}

function throws() {
  throw new Error("It threw");
}

async function asyncSum(first, second) {
  return first   second;
}

async function asyncThrows() {
  throw new Error("It throws async");
}

// returns a sum
// prints [ undefined, 2 ]
console.log(tryCatch(Math.sqrt, 4));

// returns an error
// prints [ Error: 'It threw', undefined ]
console.log(tryCatch(throws));

// returns a promise resolving to value
// prints [ undefined, 3 ]
console.log(await tryCatch(asyncSum, 1, 2));

// returns a promise resolving to error
// prints [ Error: 'It throws async', undefined ]
console.log(await tryCatch(asyncThrows));

オリジナルのバージョンとよく似ていますが、Promise ベースのコードがいくつか含まれています
念のため投入。この実装を使用すると、非同期関数を呼び出すときに tryCatch を呼び出すことができ、非同期関数を呼び出すときに await tryCatch を呼び出すことができます。

Promise ビットを見てみましょう:

if (result.then) {
  return new Promise(resolve => {
      result
        .then(v => resolve([undefined, v]))
        .catch(e => resolve([e, undefined]))    
  }); 
}

if (result.then) は、指定された関数 (apply で呼び出された) が Promise を返したかどうかを確認します。そうなった場合は、自分で Promise を返す必要があります。

result.then(v =>solve([unknown, v])) を呼び出すと、何もスローされない場合、Promise は指定された関数が返した値に解決されます。

.catch(e =>solve([e, unknown])) は少し複雑です。最初に書いたのは
.catch(e => accept([e, unknown])) となりますが、キャッチされないエラーが発生します
tryCatch から外れます。
を返すため、ここで解決する必要があります。 配列、エラーをスローしません。

そして最後に

私はかなり定期的に、試したり捕まえたりする必要があるが、次のように感じることがあります
明示的な try/catch ブロックは大量のスペースを占有し、スコープ指定の割り当てにとって煩わしいものになります。使うかどうかは分かりませんが、ちょっとした探検で楽しかったです。

リリースステートメント この記事は次の場所に転載されています: https://dev.to/nalanj/safe-assignment-44g7?1 侵害がある場合は、[email protected] に連絡して削除してください。
最新のチュートリアル もっと>

免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。

Copyright© 2022 湘ICP备2022001581号-3