Date and time format problems

The front end often needs to deal with the format of Date and time. It is very likely that the compatibility pit will be encountered when you tune the Date API to do the conversion. The reason is that the JS engine of different browsers implements different standards.

The best option in business is to use mature method libraries such as date-fns, moment, day.js.

If it is found that there is a large lump of date string parsing, conversion, and assembly logic in the business code, it is most likely because there is a problem with the data format convention at the front and back end. The general principle I recommend is that interface parameters and returned data, date-time fields are all time-stamped, and the specific presentation format is handled by the front end and the back end does not care about formatting operations. In practice, there are two advantages:

  • Avoid elemental-UI date picker default time format “bug” caused by toISOString time zone issues
  • Reaching an agreed agreement can improve the efficiency of collaboration

Due to the issues related to the release and user update cycle of Native App, it is better to return the date after formatting by the interface, but the parameter is still recommended to use the timestamp.

Read more: Shi Jun He’s joke on Date API


The current time problem

Can the front end get the exact current Beijing time? The code gets the time provided by the operating system. If the user just changes the time zone, it can correct the time zone itself, but if the user changes the system time, it can’t. Therefore, it is risky for the front-end to take the current time, especially for cross-time zone services such as international airline tickets, where the current time must be provided by the interface.


Floating point operation precision problem

This is a basic common sense of computer operations, all kinds of programming languages floating point number four operations will encounter accuracy problems (see Why 0.1 + 0.2 ≠ 0.3 in JavaScript).

In business development, especially when the amount calculation is involved, if it has to be calculated by the front end, it is best to convert it into an integer, and the unit is divided into minutes, and the front and back ends reach an agreement (Java Development Manual of Ali clearly stipulates that: any monetary amount is stored in the smallest monetary unit and integer type).

You can also use libraries that support error-free precision operations, such as currency.js and big.js.

Give a question to feel the trouble of floating point operation: how to convert 0.01 ~ 0.99 decimal into common sense to fold as a unit of expression, such as 0.2 fold, 7.5 fold, 8 fold.


Do not use toFixed as rounding

Math.round is only accurate to integers, but to round to decimal places, some people might use toFixed, but toFixed is not designed for rounding, and different browsers implement it differently. See javaScript for toFixed() accuracy issues.

An easy workaround for rounding floating-point numbers is:

const round = (n, d) = > Math.round(n * Math.pow(10, d)) / Math.pow(10, d) // d indicates the exact number of digits
Copy the code

However, this scheme suffers from the same precision problems as before, such as round(1.005, 2) returning 1 instead of 1.01 because 1.005 * 100 = 100.49999999999999.

The solution can be the Round method in MathJS, which considers a large number of cases and is relatively complete.


Integer range overflow problem

Js Number, the specification is 64-bit double precision floating point Number (IEEE 754), the finite bit encoding scheme can only represent a part of the Number on the continuous Number line, The range of integers that IEEE 754 can accurately and continuously represent is number. MIN_SAFE_INTEGER to number. MAX_SAFE_INTEGER. MAX_SAFE_INTEGER + 1 === number. MAX_SAFE_INTEGER + 2 because the binary code behind the two numbers is the same.

So large numbers like order ID must be represented as strings. ECMAScript 2021 provides a new raw data type, BigInt, that also solves this problem.


The localStorage is full

Usually in large companies, there may be dozens or hundreds of business lines under the same domain name, and each business line may plug things into localStorage for various reasons, such as cross-page data transmission, caching, offline, performance optimization… So 5M looks like a lot, but it’s going to run out pretty quickly. So a business process that relies on localStorage without considering full storage is at risk.

The basic idea is to “hurt each other” : when the storage is full, the other people’s data clear, specific reference: localStorage is full how to do.


The Url is too long

It is usually caused by unrestrained use of URL to transfer parameters across pages. One or more parameters may break the limit of the container (browser, Webview, wechat), or even exceed the limit of the server, resulting in 414 request-URI Too Long.

It is even heard that cookies are used for cross-page parameter transfer, which not only affects interface performance, but also easily leads to 413 exceptions

SessionStorage does not exist across TAB/webView, nor is it suitable for sessionStorage to exist across TAB/webView.


A try catch scenario must be added

In general, json. parse and encodeURIComponent are definitely needed unless you trust (and preferably not so much) the incoming data source.

SyntaxError: JSON Parse error: Unexpected Identifier “object” Or take a look at this list to see how error-prone Json.parse is.

“Await” in async functions also requires a try catch. It is better to have one “await” package per “try catch” and not to have multiple “await” packages in a big try catch. Then it is difficult to know from which asynchronous logic the exception is being thrown.


Promise usage questions

Case 1: Promise forgot to catch and reported a bunch of uncaught exceptions

Case 2: If a promise is executed after a reject (throw Error or return rejection), then is executed after a catch (reject). If a promise is executed after a reject (throw Error or return rejection), then is executed after a catch. And the Error from Rejected is passed to the THEN as an argument

// Classic examples of misuse
function fetchData () {
  return request('/api/path').then(d= > d.data).catch(e= > alert(e.msg))
}
fetchData().then(d= > handleData(d))
Copy the code

Case 3: The new callback Hell


Js compatibility issues

If Babel fails to compile with too high a version of the JS feature or browser API, or if it misses a compilation and then polyfills it, it will report a SyntaxError.

Keep in mind that js in node_modules will not be compiled by Babel in most project configurations, and modern scaffolding often provides configurations to solve this problem.

Polyfills are always bulky, since most user devices probably won’t use them, so it’s worth considering introducing polyfills on demand.

// A simple reference on demand approach
window.fetch || document.write('<script src="fetch-polyfill.js"></script>')
Copy the code

After build, use es-Check to check if es6 code is not compiled. But there’s a better option: Modern Build mode.


Module writing mixed problems

Uncaught TypeError: Cannot assign to read only property 'exports' of object '#<Object>'
Copy the code

Module. exports: a common trap since Webpack 2, module.exports became read-only, so assigning it an error. You can find a full discussion here.

To put it simply, WebPack 2 tweaked the modularity approach by forcing import files (which would be considered ES6 modules) to be exported only instead of using commonJS syntax, in order to address the historical problem of module syntax mixing.

The problem doesn’t end there, though. Suppose you have a CommonJS syntax for NPM packages, and since the module is not pre-compiled, you add it to the Babel compilation scope. Commonjs modules that Babel handles, however, are inserted into import, are treated as ES6 modules by Webpack, and module.exports is set to read-only. Before commonJS modules are processed by Babel, WebPack treats them as CommonJS modules and does not report errors.

That’s why Babel has a sourceType configuration.

In general, be careful of modules in your projects that still use commonJS syntax.


Module export mode

There are a number of issues to be aware of when writing tree-shaking friendly modules, such as the fact that commonJS modules are definitely not tree-shaking (it’s a convention, not a syntax, and you can’t do static analysis). Exporting an entire large object is not tree-shaking.

// don't
export default {
    functionA () {},
    functionB () {}
    ...
}

// do
export function A () {}
export function B () {}
Copy the code


Do not add export to a private method inside a module. Export is the Java equivalent of the public modifier. Once exported, the method cannot be modified or deleted during refactoring because it is not known where it will be imported. The method without export is equivalent to private and can be changed within the module.


Module introduction mode

A bunch of files, you import me, I import you, anybody worried about circular references. Not all circular references will fail, if they do, it will be Max Callstack Size exceeded. If you don’t know if there will be a problem, consider using the circular-dependency plugin to help spot it.

One reason for the confusion of module reference relation is the unreasonable design of module organization structure. So someone provided a tool to constrain and optimize the module reference structure.


Multiple versions of repeated dependencies lead to conflicts

Js’s package management mechanism, NPM, allows projects to rely on different versions of the same package, which can cause some problems. The simplest scenario assumes that a package provides the API through global variables and that the project uses the API available in a new version. Later, because the old version of the package was introduced and the loading sequence of the old version of the package was later, if the global variables of the new version of the package were overwritten directly, an error was reported when the API of the new version was called.

When a business pulls out multiple common business packages, it is easy to create multi-versioning problems. Ideally:

The upper business project | - public package A v1.0 | - public pack v2.0 | B - bag - C v3.0Copy the code

If you add the following item to your dependencies, you need to add the following item to your dependencies:

The upper business project | - public package A v1.0 | - public package B v2.1 | - public pack v2.0 | B - bag - C v3.0Copy the code

This results in the same page calling B’s methods (import XXX from B), some from v2.0 and some from V2.1. Following the principle that “anything that can go wrong will go wrong”, as long as there are multiple versions and methods called separately, something will go wrong. Even if there is no problem, the package size will be affected by repeated packaging.

The solution is to ensure that the import XXX from B in the project can only have one version of B, which can be constrained by peerDependencies, YARN Resolutions, or by NPM dedupe.


TypeScript

TypeScript deserves to be part of the infrastructure of the project. Ts has a number of clear benefits:

  • Quality assurance, finding some problems (type errors, missing parameters, forgetting to void, spelling errors, etc.)
  • Natural documentation
  • Code autocomplete prompt
  • Provides API type descriptions that constrain others’ usage

Wouldn’t it be nice to have another solution to help you find the problem


Some people may think that defining a type is cumbersome, but in fact, type validation will save you a lot of time in later maintenance. It’s not uncommon for you to change code somewhere, only to discover that something else needs to be changed, or simply to misspell a letter in a name. If there’s ts, you might already be reporting an error.


Vue & TypeScript

How Vue users use TS is a problem. Due to historical reasons, Vue’s support for TS was not as complete as React’s, so there was a vue-class-Component modeled after React.

When yuxi announced the vue3.0 development plan on September 30, 2018, it proposed the native support for the Class API and issued the RFC on February 26, 2019. The basic motivation was: since a lot of people are already developing with vue-class-Component + TS, it would be better to provide native support for the convenience of users without having to maintain another vue-class-Component.

On May 21, 2019, You Rejected the proposal on the grounds that the implementation was too complex and problematic, and that a better alternative, called composition Function, had been found. The new solution, compared to the Class API, has better reusability, better TS support, better forward compatibility, and a smaller package size.

Decorator /class is just a preference, does not solve additional problems, and may even cause additional problems, known as:

  • Causes eslint-plugin-Vue to fail to detect certain issues, such as components that are registered but not used
  • The props pass parameter could not verify the type
  • Life cycles and methods are often confused in class

In fact, vue. extend is almost sufficient for TS checks. Vue did go out of its way to support TS.