ホームページ >ウェブフロントエンド >jsチュートリアル >JavaScript を使用した開発について知っておくべきこと
冒頭の概要
Gmail での Ajax テクノロジーの適用と高性能 V8 エンジンの導入により、複雑な対話を伴う Web アプリケーションの作成もフロントエンド テクノロジーを使用して作成できるようになりました。ネイティブ アプリケーションと比較して、Web アプリケーションには次の利点があります。
クロスプラットフォームで、開発とメンテナンスのコストが低い。
アップグレードと公開が簡単で、バージョンの概念がなく、いつでもどこでも、ユーザーが意識することなく公開できる。インストールは必要ありません。
レスポンシブ レスポンシブ デザインにより、Web アプリケーションをクロスプラットフォームにでき、同じコードでさまざまな画面サイズに適応できます
最終的に Web アプリケーション ソリューションが採用されなかったとしても、依然として非常に優れています。プロトタイプの開発に適しています
もちろん、Web アプリケーションには欠点がないわけではありません。異なるプラットフォームやメーカーのブラウザはまったく同じではないため、クロスプラットフォーム互換性のコストも発生します。また、Web アプリケーションのパフォーマンスはネイティブ アプリケーションほど良くなく、HTML5 API の制限と相まって、一部の機能では Web アプリケーションの使用に適さない場合があります。これらの理由から、両方の利点を組み合わせたハイブリッド ソリューションが普及しています (たとえば、WeChat、モバイル QQ、およびモバイル QQ ブラウザには一部の Web ページが埋め込まれます)。
ここでは、著者の開発経験に基づいて、Web アプリケーションの開発中に直面する必要があるいくつかの問題を要約します。
モジュール式プログラミング
モジュール式プログラミングは、他の主流のプログラミング言語と比較して、モジュール間の依存関係を維持することはおろか、モジュールに対する直接のサポートも提供しないため、JavaScript コードの保守が非常に困難になります。コードが 3f1c4e4b6b16bbbd69b2ee476dc4f83a タグに含まれる順序は手動でメンテナンスする必要があります。
モジュール式プログラミングをサポートするには、次の 2 つの問題を解決する必要があります:
名前の競合とグローバル変数の使用を防ぐためのモジュールの作成と名前付けをサポートします。
指定されたモジュール間の依存関係の表示をサポートし、プログラムの実行時にそれらを自動的に実行します。モジュール。
書籍『Javascript: The Good Parts』で Douglas Crockford によって提案されたモジュール パターンは、JavaScript のクロージャ テクノロジを使用してモジュールの概念をシミュレートし、名前の競合やグローバル変数の使用を防ぎます。これで最初の問題は解決します。
var moduleName = function () { // Define private variables and functions var private = ... // Return public interface. return { foo: ... }; }();
2 番目の問題を解決するために、CommonJS 組織は、開発者が指定されたモジュール間の依存関係を表示し、必要に応じて依存モジュールをロードできるようにする AMD 仕様を定義しました。 RequireJS は、AMD 仕様の一般的な実装です。
最初に a.js でモジュール A を定義します。
define(function () { return { color: "black", size: 10 }; });
次に、モジュール A に依存するモジュール B を定義します。
define(["a"], function (A) { // ... });
モジュール B が実行されると、RequireJS はモジュール A がロードされていることを確認します。具体的な詳細については、RequireJS 公式ドキュメントを参照してください。
スクリプトのロード
スクリプトをロードする最も簡単な方法は、スクリプトを 93f0f5c25f18dab9d176bd4f6de5d30e にロードすることです。
<head> <script src="base.js" type="text/javascript"></script> <script src="app.js" type="text/javascript"></script> </head>
欠点は次のとおりです。
読み込みと解析が順番に同期的に実行され、次に Base.js がダウンロードされ、次に解析されて実行され、その後 app.js がダウンロードされます。
スクリプトの読み込み時に、 3f1c4e4b6b16bbbd69b2ee476dc4f83a DOM 要素のレンダリング。
これらの問題を軽減するために、現在では 3f1c4e4b6b16bbbd69b2ee476dc4f83a を 6c04bd5ca3fcae76e30b72ad730ca86d の最後に配置するのが一般的です。
<script src="base.js" type="text/javascript"></script> <script src="app.js" type="text/javascript"></script> </body>
ただし、すべてのスクリプトを 6c04bd5ca3fcae76e30b72ad730ca86d の下部に配置できるわけではありません。たとえば、ページのレンダリング時に一部のロジックを実行する必要がありますが、ほとんどのスクリプトにはそのような要件はありません。
6c04bd5ca3fcae76e30b72ad730ca86d の最後にスクリプトを配置しても、順次ダウンロードの問題は解決されません。一部のブラウザ メーカーもこの問題を認識しており、非同期ダウンロードをサポートし始めています。 HTML5 は標準ソリューションも提供しています。 async 属性でマークされた
<script src="base.js" type="text/javascript" async></script> <script src="app.js" type="text/javascript" async></script>
スクリプトは、その中で document.write などのコードを使用しないことを示します。ブラウザはこれらのスクリプトを非同期的にダウンロードして実行し、DOM ツリーのレンダリングを妨げません。しかし、これは別の問題を引き起こします。非同期実行により、app.js が Base.js より前に実行される可能性があり、それらの間に依存関係がある場合にエラーが発生します。
そういえば、開発者の観点から見ると、実際に必要なのは次の機能です:
非同期ダウンロード、DOM のレンダリングをブロックしません。
モジュールの依存関係に従ってスクリプトを解析して実行します。
つまり、スクリプトの読み込みは、実際にはモジュール式プログラミングの問題と併せて解決する必要があります。 RequireJS はモジュール間の依存関係を記録するだけでなく、依存関係に基づいたオンデマンドの読み込みと実行も提供します (詳細については、RequireJS 公式ドキュメントを参照してください)。
スクリプトの読み込みに関するその他の解決策については、こちらを参照してください。
静的リソース ファイルのデプロイメント
ここでの静的リソース ファイルとは、CSS、JavaScript、および CSS に必要ないくつかの画像ファイルを指します。導入では、次の 2 つの問題を考慮する必要があります:
ダウンロード速度
バージョン管理
静的リソース ファイルの特徴の 1 つは、変更が少なく、ユーザー ID とは関係がない (つまり、Cookie とは関係がない) ため、キャッシュに非常に適していることです。一方、静的リソース ファイルが変更されると、ブラウザは Web サーバーから最新バージョンをダウンロードする必要があります。 Web アプリケーションの新しいバージョンがリリースされても、すべてのユーザーがすぐに新しいバージョンを使用するとは限らず、古いバージョンと新しいバージョンが共存するため、バージョンの一致の問題が発生します。古いバージョンのアプリケーションは古いバージョンの CSS と JavaScript をダウンロードする必要があり、新しいバージョンのアプリケーションは新しいバージョンの静的リソースをダウンロードする必要があります。
バージョンの不一致を防ぐために、アプリケーションの新しいバージョンがリリースされるたびに、古い HTML が古い静的ファイルを参照し、新しい HTML が新しい静的ファイルを参照するように、静的リソース ファイルの名前を変更する必要があります。一般的なアプローチは、ファイル名にタイムスタンプを追加することです。
未解決の参照を防ぐために、リソース ファイルは HTML よりも前に公開する必要があります。
上記の解決策は、バージョンの問題を解決できるため、各静的ファイルのキャッシュ時間を任意に大きく設定して、繰り返しダウンロードを防ぐことができ、同時に、新しいバージョンがリリースされるときにブラウザーが更新されます。 。
ダウンロード速度の問題を解決するには、次の解決策を検討できます:
ファイルが多すぎると、ダウンロードにさらに多くの接続が必要になるのを避けるために、ブラウザには通常、同じドメイン名の接続数に制限があります。 ;
静的ファイルを圧縮します。CSS と Javascript には通常、多くの空白行、インデント、コメントが含まれていますが、これらは公開時に削除できます。
静的ファイルは通常、Cookie とは関係がないため、転送サイズ また、キャッシュ ヒット率を高めるには (キャッシュされたキーは Cookie を考慮する必要があります)、静的ファイルは Cookie なしのドメイン名でホストするのが最適です
最後で最も重要なことは、上記のプロセスを自動化する必要があります。
MVC プログラミング モデル
Web アプリケーションは、ネイティブ アプリケーションと同じイベント駆動型プログラミング モデルを使用します。唯一の違いは、インフラストラクチャによって提供される API が異なることです。 UI プログラミングは通常、MVC デザイン パターンを採用します。人気のある Backbone.js を例に挙げると、次の部分が含まれます:
モデル
データの唯一のソース
データの取得と保存を担当します
キャッシュ メカニズムを提供できます
データ変更時にイベントを通じて通知
他のオブジェクト
View
がレンダリングを担当します
UIイベントとModelイベントをリッスンしてUIを再描画します
レンダリング結果は2種類のデータに依存します:モデルとUIのインタラクション状態
UI インタラクション状態は通常 View オブジェクトに存在しますが、便宜上 DOM ツリー ノードに存在することもあります
レンダリング コストを削減するために、レンダリングする必要がある領域を削減し、データが変更されるたびに影響を受ける領域のみをレンダリングするようにしてください。
Router
は、URL の変更を監視し、対応する View オブジェクトに通知することを担当します。 ページのレンダリング
MVC を効果的に使用するには、注意する必要がある問題がいくつかあります。
Model は View から完全に分離される必要があります
Model はデータへのアクセスのみを提供し、View に依存すべきではないため、Model は View の存在を認識すべきではありません。したがって、Model は View オブジェクトへの参照を保持できません。モデルのデータが変更されると、イベントを通じてのみビューに通知できます。
View は初期化中にデリゲーションを使用して UI イベントをリッスンします。ここには 2 つの重要なポイントがあります:
初期化中にイベントをリッスンする var View = Backbone.View。 extend( {Initialize: function () { this.$el.on('click', '#id', function () { // … }); } });
一部の特殊なケースを除く (下記を参照) , 同じイベントが複数回バインドされないように、ビューの初期化時にすべての UI イベントを初期化する必要があります。一部のイベントが動的に監視される場合でも (監視が必要な場合もあれば、監視が不要な場合もあります。たとえば、一部のボタンが有効な場合と無効な場合があります)、初期化中に監視し、イベント コールバック関数で判断する必要があります。加工が必要です。これにより、ロジックがシンプルになり、保守が容易になります。
委任メソッドを使用して UI イベントを監視します
委任メソッドの監視については、jQuery のドキュメントを参照してください。
イベントは初期化中に監視する必要があることを上で強調しましたが、初期化中に監視する必要がある DOM ノードは、まだ存在しないため、イベントを直接バインドすることはできません。ただし、委任方法では、イベントがバブルアップする可能性があることが必要です。
バブルできないイベント (a1f02c36ba31691bcfe87b2722de723b のロード イベントなど) については、その存在が保証されている場合にのみ直接バインドでき、必ずしも初期化中にバインドできるわけではありません。
複雑なビューはツリー階層構造に編成されています
関数が大きすぎるため、いくつかのサブ関数に分割する必要があります。同様に、ビューのロジックが複雑すぎる場合は、ページ構造に従って複数のサブビューに分割する必要があります:
親ビューは参照を通じてサブビューにアクセスしますが、サブビューはへの参照を保持すべきではありません。親ビュー。
サブビューは独自の領域のレンダリングのみを担当し、他の領域は親ビューによってレンダリングされます。
親ビューは関数呼び出しを通じて子ビューの機能にアクセスし、子ビューは子ビューと通信します。親ビューはイベントを通じて
子ビューは直接通信できません。
その他のヒントについては、「バックボーン テクニックとパターン」を参照してください。
オフライン アプリケーション キャッシュ
Web アプリケーションのエクスペリエンスをよりスムーズにするために、HTML5 オフライン アプリケーション キャッシュの使用を検討できますが、次の点に注意してください。オフライン アプリケーション キャッシュと HTTP キャッシュ メカニズムの組み合わせは混乱を招きます。前者は HTML5 によって導入された新機能であり、HTTP キャッシュ メカニズムとは独立して共存します。
Cache manifest文件不应被HTTP缓存太久(通过HTTP头Cache-Control控制缓存 时间),否则发布新版后浏览器不会及时监测到变化并下载新文件;
在Cache manifest文件的NETWORK节放一个*,否则没有列在这个文件的资源不 会被请求;
不适合缓存的请求最好都放在NETWORK节;
如果之前使用过离线应用缓存现在不想再使用了,从100db36a723c770d327fc0aef2ce13b1删除manifest属性, 并发送404响应给manifest文件请求。仅仅删除manifest属性是没有效的。
线上错误报告
Javascript是一个动态语言,许多检查都是在运行时执行的,所以大多数错误只有执行到的时候才能检查到,只能在发布前通过大量测试来发现。即使这样仍可能有少数 没有执行到的路径有错误,这只能通过线上错误报告来发现了。
window.onerror = function (errorMsg, fileLoc, linenumber) { var s = 'url: ' + document.URL + '\nfile: ' + fileLoc + '\nline number: ' + linenumber + '\nmessage: ' + errorMsg; Log.error(s); // 发给服务器统计监控 console.log(s); };
通常线上的Javascript都是经过了合并和压缩的,上报的文件名和行号基本上没法对 应到源代码,对查错帮助不是很大。不过最新版的Chrome支持在onerror的回调函数 中获取出错时的栈轨迹:window.event.error.stack.