Home  >  Article  >  Web Front-end  >  What you need to know about developing using JavaScript

What you need to know about developing using JavaScript

伊谢尔伦
伊谢尔伦Original
2016-11-22 11:38:41806browse

Opening Overview

The successful application of Ajax technology in Gmail and the launch of the high-performance V8 engine have made writing web applications popular. Applications with complex interactions can also be written using front-end technology. Compared with native applications, web applications have the following advantages:

Cross-platform, low development and maintenance costs;

Easy to upgrade and publish, there is no concept of versions, and can be published anytime, anywhere, without user awareness, and no installation is required;

Responsive Responsive Design enables web applications to be cross-platform, and the same code can adapt to various screen sizes

Even if the web application solution is not adopted in the end, it is still very suitable for developing prototypes

Of course, web applications are not without their shortcomings. Since the browsers of different platforms and manufacturers are not exactly the same, there are also some cross-platform compatibility costs. In addition, the performance of web applications is not as good as that of native applications, and the interaction is sometimes not very smooth. Coupled with the limitations of the HTML5 API, it is not suitable to use web applications for some functions. For these reasons, hybrid solutions that combine the advantages of both have become popular (for example, WeChat, mobile QQ, and mobile QQ browsers will embed some Web pages).

Based on the author’s development experience, here is a summary of some problems that must be faced during the development of web applications.

Modular programming

Modular programming is an essential feature for writing large-scale applications. Compared with other mainstream programming languages, Javascript does not provide direct support for modules, let alone maintaining dependencies between modules. This makes maintaining Javascript code extremely difficult, and the order in which the code is included in the 3f1c4e4b6b16bbbd69b2ee476dc4f83a tag requires manual maintenance.

To support modular programming, two problems must be solved:

Support writing and naming modules to prevent name conflicts and the use of global variables;

Support displaying dependencies between specified modules and automatically execute them when the program is executed Load dependent modules.

The Module Pattern proposed by Douglas Crockford in the book "Javascript: The Good Parts" uses Javascript's closure technology to simulate the concept of modules and prevent name conflicts and the use of global variables. This solves the first problem.

var moduleName = function () {
    // Define private variables and functions
    var private = ...
    // Return public interface.
    return {
        foo: ...
    };
}();

In order to solve the second problem, the CommonJS organization defined the AMD specification to facilitate developers to display dependencies between specified modules and load dependent modules when needed. RequireJS is a popular implementation of the AMD specification.

First we define module A in a.js.

define(function () {
    return {
        color: "black",
        size: 10
    };
});

Then we define module B to depend on module A.

define(["a"], function (A) {
    // ...
});

When module B is executed, RequireJS ensures that module A has been loaded. For specific details, please refer to the RequireJS official documentation.

Script loading

The simplest way to load scripts is to load them in the 93f0f5c25f18dab9d176bd4f6de5d30e.

<head>
    <script src="base.js" type="text/javascript"></script>
    <script src="app.js" type="text/javascript"></script>
</head>

The disadvantage is:

Loading and parsing are executed synchronously in sequence. Base.js is downloaded first, then parsed and executed, and then app.js is downloaded;

When loading the script, it will also block the 3f1c4e4b6b16bbbd69b2ee476dc4f83a Rendering of DOM elements.

To alleviate these problems, the common practice now is to place 3f1c4e4b6b16bbbd69b2ee476dc4f83a at the bottom of 6c04bd5ca3fcae76e30b72ad730ca86d.

  <script src="base.js" type="text/javascript"></script>
    <script src="app.js" type="text/javascript"></script>
</body>

But not all scripts can be placed at the bottom of 6c04bd5ca3fcae76e30b72ad730ca86d. For example, some logic needs to be executed when the page is rendered, but most scripts do not have such a requirement.

Placing the script at the bottom of 6c04bd5ca3fcae76e30b72ad730ca86d still does not solve the problem of sequential downloading. Some browser manufacturers are also aware of this problem and begin to support asynchronous downloading. HTML5 also provides a standard solution:

<script src="base.js" type="text/javascript" async></script>
<script src="app.js" type="text/javascript" async></script>

Scripts marked with the async attribute indicate that you do not use code such as document.write in it. The browser will download and execute these scripts asynchronously and will not prevent the rendering of the DOM tree. But this will lead to another problem: due to asynchronous execution, app.js may be executed before base.js, which will cause errors if there are dependencies between them.

Speaking of which, from a developer’s perspective, what we actually need are these features:

Asynchronous download, do not block the rendering of the DOM;

Parse and execute scripts according to module dependencies.

So the loading of scripts actually needs to be solved in conjunction with modular programming issues. RequireJS not only records the dependencies between modules, but also provides on-demand loading and execution based on dependencies (please refer to the RequireJS official documentation for details).

Please see here for more solutions on script loading.

Deployment of static resource files

The static resource files here refer to CSS, Javascript and some image files required by CSS. Their deployment needs to consider two issues:

Download speed

Version management

One characteristic of static resource files is that they change infrequently and have nothing to do with user identity (that is, not related to cookies), so they are very suitable for caching. On the other hand, once the static resource file changes, the browser must download the latest version from the Web server. When a new version of a web application is released, not all users will use the new version immediately. The old version and the new version will coexist, which involves version matching issues. Older versions of applications need to download older versions of CSS and Javascript, and newer versions of applications need to download newer versions of static resources.

In order to prevent version inconsistency, the static resource files need to be renamed whenever a new version of the application is released, so that the old HTML refers to the old static files, and the new HTML refers to the new static files. A common approach is to add a timestamp to the file name;

To prevent dangling references, resource files should be published before HTML.

The above solution can solve the version problem, so that the cache time of each static file can be set to an arbitrarily large size to prevent repeated downloads. At the same time, the browser will be updated in time when a new version is released.

To solve the download speed problem, you can consider the following solutions:

Merge static files to avoid too many files. Excessive files require more connections to download. Browsers usually have limits on the number of connections for the same domain name. ;

Compress static files; For readability, CSS and Javascript usually have a lot of blank lines, indents and comments, which can be removed when publishing;

Static files usually have nothing to do with cookies, so in order to reduce the transfer size And to increase the cache hit rate (the cached key needs to consider cookies), static files are best hosted on a domain name without cookies;

Last and most important, the above process must be automated.

MVC programming model

Web applications use an event-driven programming model, which is the same as native applications. The only difference is that the API provided by the infrastructure is different. UI programming usually adopts the MVC design pattern. Taking the popular Backbone.js as an example, it includes the following parts:

Model

The only source of data

Responsible for obtaining and storing data

Can provide caching mechanism

Notify through events when data changes Other objects

View

are responsible for rendering

listen to UI events and Model events and redraw the UI

The rendering result depends on two types of data: Model and UI interaction state

UI interaction state usually exists in the View object, sometimes for Convenience also exists in DOM tree nodes

In order to reduce rendering costs, try to reduce the area that needs to be rendered, and only render the affected area every time the data changes

Router

is responsible for monitoring URL changes and notifying the corresponding View object Rendering the page

In order to use MVC effectively, there are several issues that need to be paid attention to.

Model should be completely isolated from View

Model only provides access to data and should not rely on View, so Model should not know the existence of View. So the Model cannot hold a reference to any View object. When the Model's data changes, it can only notify the View through events.

View uses delegation to listen to UI events during initialization

There are two key points here:

Listen for events during initialization var View = Backbone.View.extend( { initialize: function () { this.$el.on('click', '#id', function () { // … }); } });

Except for some special cases (see below), All UI events should be initialized when the View is initialized to prevent the same event from being bound multiple times. Even if some events are dynamically monitored (sometimes monitoring is required, sometimes no monitoring is required, for example, some buttons are sometimes valid and sometimes invalid), they still need to be monitored during initialization, and then judged in the event callback function. Needs to be processed. This makes the logic simpler and easier to maintain.

Use delegation method to monitor UI events

Please refer to the jQuery documentation for delegation method monitoring.

It has been emphasized above that the event must be monitored during initialization, but the DOM node that needs to be monitored during initialization may not exist yet, so it cannot be directly bound. Events can only be delegated. However, the delegation method requires that events can bubble up.

For those events that cannot bubble (such as the load event of a1f02c36ba31691bcfe87b2722de723b), they can only be bound directly if their existence is guaranteed, and not necessarily during initialization.

Complex View is organized into a tree hierarchical structure

The function is too large and needs to be split into several sub-functions. Similarly, if the logic of the View is too complex, it should be split into several sub-Views according to the page structure:

The parent View accesses the sub-View through references, but the sub-View should not hold references to the parent View;

The sub-View is only responsible for its own area Rendering, other areas are rendered by the parent View;

The parent View accesses the functions of the child View through function calls, and the child View communicates with the parent View through events;

The child Views cannot communicate directly.

For other tips, check out Backbone Techniques and Patterns.

Offline Application Cache

To make the web application experience smoother, you can consider using HTML5 offline application cache, but there are the following points to note:

Do not combine offline application cache with The HTTP caching mechanism is confusing. The former is a new feature introduced by HTML5, and it coexists independently with the HTTP caching mechanism;

Cache manifest文件不应被HTTP缓存太久(通过HTTP头Cache-Control控制缓存 时间),否则发布新版后浏览器不会及时监测到变化并下载新文件;

在Cache manifest文件的NETWORK节放一个*,否则没有列在这个文件的资源不 会被请求;

不适合缓存的请求最好都放在NETWORK节;

如果之前使用过离线应用缓存现在不想再使用了,从100db36a723c770d327fc0aef2ce13b1删除manifest属性, 并发送404响应给manifest文件请求。仅仅删除manifest属性是没有效的。

线上错误报告

Javascript是一个动态语言,许多检查都是在运行时执行的,所以大多数错误只有执行到的时候才能检查到,只能在发布前通过大量测试来发现。即使这样仍可能有少数 没有执行到的路径有错误,这只能通过线上错误报告来发现了。

window.onerror = function (errorMsg, fileLoc, linenumber) {
    var s = &#39;url: &#39; + document.URL + &#39;\nfile: &#39; + fileLoc
       + &#39;\nline number: &#39; + linenumber
       + &#39;\nmessage: &#39; + errorMsg;
    Log.error(s); // 发给服务器统计监控
    console.log(s);
};

通常线上的Javascript都是经过了合并和压缩的,上报的文件名和行号基本上没法对 应到源代码,对查错帮助不是很大。不过最新版的Chrome支持在onerror的回调函数 中获取出错时的栈轨迹:window.event.error.stack.


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn