Using Sidecar to introduce Node.js into Spring Cloud

theory

brief introduction

Spring Cloud is a popular micro service solution at present. It combines the convenient development of Spring Boot with the rich solution of Netflix OSS. As we all know, Spring Cloud is different from Dubbo and uses Rest services based on HTTP (s) to build the whole service system.

Is it possible to develop some Rest services using some non JVM languages, such as Node.js, which we are familiar with? Yes, of course. However, if only Rest services are available, it is not possible to access the Spring Cloud system. We also want to use the Eureka provided by Spring Cloud for service discovery, use Config Server to do configuration management, and use Ribbon to do client load balancing. At this point, Spring sidecar will be able to show its talents.

Sidecar originated from Netflix Prana. He provides a HTTP API that allows access to all instances of established services, such as host, ports, etc. You can also use an embedded Zuul proxy service to get the relevant routing nodes from Eureka. Spring Cloud Config Server can be accessed directly through the host or through proxy Zuul.

What you need to be aware of is the Node.js application you have developed, and you have to implement a health check interface to allow Sidecar to report the health of this service instance to Eureka.

In order to use Sidecar, you can create a Spring Boot program with @EnableSidecar annotation. Let’s look at what this annotation has done.

@EnableCircuitBreaker

@EnableDiscoveryClient

@EnableZuulProxy

@Target (ElementType.TYPE)

@Retention (RetentionPolicy.RUNTIME)

@Documented

@Import (SidecarConfiguration.class)

Public @interface EnableSidecar {

}

Look, hystrix fuse, Eureka service discovery, zuul agent, all of these components have been opened.

Health examination

Next, we need to add the configuration of sidecar.port and sidecar.health-uri in application.yml. The sidecar.port attribute represents the port of the Node.js application listener. This is to enable sidecar to register in Eureka services. Sidecar.health-uri is a URI that simulates the interface of Spring Boot application health indicators. It must return the following form of JSON document: health-uri-document

{

" status": " UP"

}

The application.yml of the entire Sidecar application is as follows: application.yml

Server:

Port: 5678

Spring:

Application:

Name: sidecar

Sidecar:

Port: 8000

Health-uri: http://localhost:8000/health.json

Service access

After building this application, you can use /hosts/{serviceId} API to get the result of DiscoveryClient.getInstances (). Here is an example of returning two instances of information from different /hosts/customers from host. If sidebar runs on the 5678 port, then the Node.js application can access the API through http://localhost:5678/hosts/{serviceId}.

/hosts/customers

[

{

" host": " myhost"

" port": 9000,

" uri": " http://myhost:9000"

" serviceId": " CUSTOMERS"

" secure": false

},

{

" host": " myhost2"

" port": 9000,

" uri": " http://myhost2:9000"

" serviceId": " CUSTOMERS"

" secure": false

}

]

Zuul proxy can automatically be registered to the Eureka association to /< serviceId> services add routing, so customer services can be accessed via the /customers URI. It is also assumed that sidecar listens on the 5678 port, so that our Node.js application can access the customer service through http://localhost:5678/customers.

Config Server

If we use the Config Server service and register it to Eureka, Node.js application can access it through Zull Proxy. If ConfigServer’s serviceId is configserver and Sidecar listens on the 5678 port, then you can access Config Server via http://localhost:5678/configserver. Of course, this is also due to Eureka, Config Server provides Rest interface based on HTTP protocol.

Node.js applications can also use the capabilities of Config Server to get some configuration documents, such as YAML format. For example, an access to http://sidecar.local.spring.io:5678/configserver/default-master.yml might get the following YAML document back:

Eureka:

Client:

ServiceUrl:

DefaultZone: http://localhost:8761/eureka/

Password: password

Info:

Description: Spring Cloud Samples

Url: https://github.com/spring-cloud-samples

So the whole architecture of Node.js application accessing to Spring Cloud micro service cluster through Sidecar is roughly shown as follows:

Demo practice

Let’s suppose that there is such a very simple data. It is called User:

Class User {

Private Long ID;

Private String username;

Private Integer age;

}

It looks very classic, Kazakhstan!

Another data structure is used to represent books, Book:

Class Book {

Private Long ID;

Private Long authorId;

Private String name;

Private String publishDate;

Private String des;

Private String ISBN;

}

The authorId in Book corresponds to the ID of User. Now we need to develop Rest services for these two data.

First, User, we use spring to develop, first in the controller construction method, mock some false data users, and then a very simple Get interface based on the ID user.

@GetMapping (" /{id}")

Public User findById (@PathVariable Long ID) {}

After starting, we curl visited:

Curl localhost:8720/12

{" id"; 12; " username&quot:; " user12" " age&quot: 16}

Next, we use Node.js to develop Book related interfaces.

Because the Node.js community is very active, the optional Rest service framework is very large. The mainstream is express, KOA, hapi, and so on, very lightweight and easy to extend like connect. Here I consider the mass base and document richness, and choose to use express to develop such a Rest service that can be connected to Spring Cloud.

Const express = require (‘express’)

Const faker = require (‘faker/locale/zh_CN’)

Const logger = require (‘morgan’)

Const services = require (‘./service’)

Const app = Express ()

Let count = 100

Const books = new Array (count)

While (count > 0) {

Books[count] = {{

Id: count,

Name: faker.name.title (),

AuthorId: parseInt (Math.random () * 100) + 1,

PublishDate: faker.date.past ().ToLocaleString (),

Des: faker.lorem.paragraph (),

ISBN: `ISBN 000-0000-00-0`

}

Count —

}

App.use (logger (‘combined’))

/ / service health index interface

App.get (‘/health’, (req, RES) => {

Res.json ({

Status:’UP’

})

})

App.get (‘/book/: id’, (req, res, next) => {

Const id = parseInt (req.params.id)

If (isNaN (ID)) {

Next ()

}

Res.json (books[id])

})

/ /…

First, use faker to mock100 data, then write a simple get routing.

After startup, we visit http://localhost:3000/book/1 with browser.

Now that we have two micro services, next we launch a Sidecar instance to connect Node.js to Spring Cloud.

@SpringBootApplication

@EnableSidecar

Public class SidecarApplication {

Public static void main (String[] args) {

SpringApplication.run (SidecarApplication.class, args);

}

}

Very simple, it needs to be noted that before this, you need a eureka-server to test the ability of the sidecar agent to access Spring Config, and I also use config-server, believing that students who are familiar with spring cloud should know.

In the configuration of sidecar, bootstrap.yaml simply specifies the address of the service port and the config-server, and the node-sidecar.yaml configuration is as follows:

Eureka:

Client:

ServiceUrl:

DefaultZone: ${EUREKA_SERVICE_URL:http://localhost:8700/eureka/}

Sidecar:

Port: 3000

Home-page-uri: http://localhost:${sidecar.port}/

Health-uri: http://localhost:${sidecar.port}/health

Hystrix:

Command:

Default:

Execution:

Timeout:

Enabled: false

Here we specify the address of the node.js service directed by sidecar, and hystrix.command.default.execution.timeout.enabled: false is mainly because sidecar uses hystrix’s default timeout fuse, and the speed of domestic access to GitHub, as you know, I often timeout of config-server when I test, so I put it If you drop out of disable, you can choose to extend the overtime time.

When eureka-server, config-server, user-service, node-sidecar, node-book-service are all started, we open the http://localhost:8700/ of the main page of Eureka:

See that our services are in UP state, indicating that everything is normal. Next, look at the console of the Node.js application:

It is found that there is already traffic coming in, and the access interface is /health. Obviously, this is node-sidecar’s call to check the health of our node application.

Next is the time to witness miracles. Our curl visits the 8741 port of sidecar:

Curl localhost:8741/user-service/12

{" id"; 12; " username&quot:; " user12" " age&quot: 16}

Consistent with the results of direct access to user-service, it shows that sidecar Zuul Proxy can proxy our request to user-service services.

Well, with this agent, we hope that book services can provide the interface of author information:

Const SIDECAR = {{

Uri:’http://localhost:8741′

}

Const USER_SERVICE =’user-service’

Const getUserById = (ID) => fetch (`${SIDECAR.uri}/${USER_SERVICE}/${id}`).Then ((RESP) => resp.json ())

App.get (‘/book/: bookId/author’, (req, res, next) => {

Const bookId = parseInt (req.params.bookId)

If (isNaN (bookId)) {

Next ()

}

Const book = books[bookId]

If (Book) {

Let uid = book.authorId

Services.getUserById (uid).Then ((user) => {

If (user.id) {

Res.json (user)

}else{

Throw new Error (" user not found")

}

}).Catch ((error) => next (error))

}

})

/ / / / based on uid, filter produces all the books of authorId as UID

App.get (‘/books’, (req, res, next) => {

Const uid = req.query.uid

Res.json (books.filter ((Book) => book.authorId = = uid))

})

When we visit http://localhost:3000/book/2/author, we can see that we return the author information of bookId 2. But there is a problem here, and we can’t access the Node.js interface by accessing http://localhost:8741/node-sidecar/book/1 as the proxy to user-service, so how do you get user-service to get book-service data? Looking at the first part of theoretical knowledge, we can get access to various services by visiting /hosts/< serviceId>

TLS/SSL (Https) in Android

Recently, some technical points of Https have been dealt with in the work. Therefore, to make a combing and popularization here, this article will focus on three issues:

What is 1.Https?

How do you use Https in 2.Android?

3. how do you use Charles and other tools to capture Https links?

What is 1.Https?

The following is a clearer description and rationale of Https from the Internet.

Like Https, Http is an agreement used when we browse the web. The data transmitted by HTTP protocol is unencrypted, that is, plaintext, so it is very unsafe to use HTTP protocol to transmit privacy information. In order to ensure that these privacy data can be encrypted, the Netscape Co designed the SSL (Secure Sockets Layer) protocol to encrypt the data transmitted by the HTTP protocol, thus creating a HTTPS

HTTPS needs a handshake between the client (browser) and the server (Web site) before the data is transmitted, and in the handshake, the encryption information of the encrypted data for both sides will be established. Asymmetric encryption, symmetric encryption and HASH algorithm are used in TLS/SSL. The simple description of the handshake process is as follows:

1. the browser sends a set of encryption rules that it supports to the website.

2. the website selects a set of encryption algorithm and HASH algorithm, and sends back its identity information to the browser in the form of certificate. The certificate contains information about the website address, encrypted public key, and the issuing authority of the certificate.

3. after obtaining the website certificate, the browser has to do the following work:

A) verify the legitimacy of the certificate (whether the certificate authority is legal, whether the site address contained in the certificate is consistent with the address that is being accessed), if the certificate is trusted, the browser bar will display a small lock, otherwise the certificate will not be prompted by the letter.

B) if the certificate is trusted, or the user accepts an untrusted certificate, the browser generates a string of random numbers and encrypts it with the public key provided in the certificate.

C) use the agreed HASH to compute the handshake message, and use the generated random number to encrypt the message, and finally send all the information generated to the web site.

4. after receiving the data from the browser, the website should do the following operations:

A) use its own private key to decrypt the password, use the password to decrypt the handshake message, and verify that the HASH is consistent with the browser.

B) encrypts a handshake message with the password and sends it to the browser.

The 5. browser decrypts and calculates the HASH of the handshake message. If the HASH is consistent with the service end, the handshake process ends, after which all the communication data will be encrypted by the random password generated by the previous browser and using the symmetric encryption algorithm.

The browser and web site send encrypted handshake messages to each other and verify that the purpose is to ensure that both parties have obtained a consistent password, and that the data can be encrypted and decrypted normally to do a test for the transmission of the subsequent real data. In addition, the general encryption and HASH algorithms used by HTTPS are as follows: asymmetric encryption algorithms: RSA, DSA/DSS symmetric encryption algorithms: AES, RC4, 3DES HASH algorithms: MD5, SHA1, SHA256

The asymmetric encryption algorithm is used to encrypt the password generated during the handshake, and the symmetric encryption algorithm is used to encrypt the real data, and the HASH algorithm is used to verify the integrity of the data. Because the password generated by the browser is the key to the whole data encryption, the asymmetric encryption algorithm is used to encrypt it. Asymmetric encryption algorithm will generate public and private keys, public key can only be used to encrypt data, so it can be transferred at will, and the private key of the website is used to decrypt the data, so the web site will be very careful to keep its private key to prevent leakage.

How do you use Https in 2.Android?

The use of HTTPS in Android is divided into two kinds of security certificates and unsafe certificates. In fact, the difference in the code is not very large. There is a security certificate that is more than a certificate of loading, but it is more secure, and no certificate is easily imitated.

The following is the case of no security certificate: 1. first, we need to define HostnameVerifier (host name matching check). Here we do not check, and return to true directly, the code is as follows:

/ * * * * *

* Created by DWB on 2016/10/26.

* * /

/ / / ignore certificate HostName

Public class MeituanVerifier

Implements HostnameVerifier

{

Public MeituanVerifier (MeituanHttp paramMeituanHttp)

{

}

Public Boolean verify (String paramString, SSLSession paramSSLSession)

{

Return true;

}

}

2. then, we need to define SocketFactory, mainly to set up SSLContext (this class is responsible for certificate management and trust management), and you can see that the main load is a null (certificate manager) and a TrustAllManager (trust manager). The code is as follows:

/ / trust all certificates

Public static class AllowAllSSLSocketFactory extends SSLSocketFactory

{

Private SocketFactory socketFactory;

Private SSLContext sslContext;

Public AllowAllSSLSocketFactory ()

{

Try

{

This.sslContext = SSLContext.getInstance (" TLS");

TrustAllManager trustAllManager = new TrustAllManager (this);

This.sslContext.init (null, new TrustManager[] {trustAllManager}, new SecureRandom ());

This.socketFactory = this.sslContext.getSocketFactory ();

Return;

}

Catch (NoSuchAlgorithmException localNoSuchAlgorithmException)

{

LocalNoSuchAlgorithmException.printStackTrace ();

}

Catch (KeyManagementException localKeyManagementException)

{

LocalKeyManagementException.printStackTrace ();

}

}

}

Import java.security.cert.CertificateException;

Import java.security.cert.X509Certificate;

Import javax.net.ssl.X509TrustManager;

/ * * * * *

* Created by DWB on 2016/10/26.

* * /

Public class TrustAllManager implements X509TrustManager {

Public TrustAllManager (HttpUtil.AllowAllSSLSocketFactory paramAllowAllSSLSocketFactory)

{

}

@Override

Public void checkClientTrusted (X509Certificate[] arg0, String arg1)

Throws CertificateException {

/ / TODO Auto-generated method stub

}

@Override

Public void checkServerTrusted (X509Certificate[] arg0, String arg1)

Throws CertificateException {

/ / TODO Auto-generated method stub

}

@Override

Public X509Certificate[] getAcceptedIssuers () {

/ / TODO Auto-generated method stub

Return null;

}

}

3. finally, set up setSSLSocketFactory and setHostnameVerifier in HttpURLConnection, for example:

Protected HttpURLConnection openConnection (Request paramRequest) throws IOException

{

LocalHttpURLConnection = super.openConnection (paramRequest);

If ((localHttpURLConnection instanceof HttpsURLConnection))

{

If (this.hostnameVerifier! = null)

((HttpsURLConnection) localHttpURLConnection).SetHostnameVerifier (this.hostnameVerifier);

If (this.socketFactory! = null)

((HttpsURLConnection) localHttpURLConnection).SetSSLSocketFactory (this.socketFactory);

}

Return localHttpURLConnection;

}

In this way, you can establish an access request for HTTPS.

3. how do you use Charles and other tools to capture Https connections?

1. first, download the Charles and download the links as follows: https://www.charlesproxy.com/download/ pay attention to download the corresponding version according to the system.

2. let the Android mobile phone and computer connected to the same LAN, and then set up the Android mobile agent, the steps are as follows: one: check the IP address of the computer, the Mac system can look under the corresponding WiFi node in the system preference setting, and Windows can look up at ipconfig under CMD, for example, this machine query is 192.168.100.7

Two: open the setup of the mobile phone – the wireless network – select the corresponding WiFi node – the advanced setting – the manual Http agent, the proxy server host name to fill in the IP that has just been queried, the proxy server port fill in the 8888: through the above steps, and then open the Charles, you can grab the request of the HTTP, as follows XX outside. Sell to get order interface Grab:

3. open Charles, Help- SSLProxying

Then, in a well connected Android phone, use Android’s own browser to enter chls.pro/ssl to download the certificate and install it as follows:

Now, you can formally grab the link of HTTPS, the following is the HTTPS order request for XX takeaway grabbing:

An Zhuozhong’s HTTPS is about to talk here! It will continue to update ~

Common command of ImageMagic and its application in Java

Baidu Encyclopedia: ImageMagick is a free software for creating, editing and synthesizing pictures. It can read, transform and write images in various formats. Image cutting, color replacement, application of various effects, rotation and combination of pictures, text, straight lines, polygons, ellipses, curves, attached to picture extension and rotation. All of its source code is open, free to use, copy, modify, and publish. It complies with the GPL license agreement. It can run in most of the operating systems.

Part of the command and introduction of 1.ImageMagick

[convert mogrify identify| composite montage compare compare display display animate import import conjure]

Convert: convert image format and size, blurred, cut, remove stains, jitter, draw pictures on the picture, add new pictures, create thumbnails, etc.

Mogrify: according to the specified size, one image, fuzzy, cropping, jitter and so on. Mogrify rewrites the original image file and writes it to a different image file.

Identify: describes the format and characteristics of one or more image files.

Composite: generate pictures based on a combination of pictures or multiple pictures.

Montage: create some separate element images. Arbitrary decorative pictures containing elements, such as borders, structures, picture names, etc.

Compare: arithmetic and visual assessment of different pictures and other transformation pictures.

Display: if you have a X server system, it can display pictures in sequence.

Animate: display animated pictures with X server

Import: output image files on X server or any visible window. You can capture a single window, the entire screen, or any rectangular part of the screen.

Conjure: explains the script that executes MSL (Magick Scripting Language).

2.ImageMagic command line and explanation

Picture cutting:

Convert -crop 100 (long) X200 (high) +10 (x coordinates) +10 (Y coordinates) dwb.jpg (source image path) dwd.jpg (after zooming storage path)

Picture compression:

Convert -sample 80×40 input.jpg output.jpg

(using a simple algorithm to generate thumbnails, fast speed, low quality, suitable for generating pictures below 100×100)

Convert -resize 100×100 dwb.jpg dwd.jpg

(good picture)

Convert -resize 50%x50% dwb.jpg dwd.jpg

Convert -resize 100×200 dwb.jpg (image path) dwd.jpg (zoom after storage path)

The picture is scaling in proportion

Convert -resize 100×200\! Dwb.jpg (image path) dwd.jpg (zoom after storage path)

Coercion at a given width and height

Note: -resize will try to keep the original length and width of the original graph (the size of the size behind it does not add ‘! “), so the image that is not necessarily generated will match the size you specify, for example, if the dwd.jpg size is 400×200, so if the command: convert dwd.jpg -resize 100×100 dwd.png, then the generated picture dwd.png. The actual size is 100×50. If you require the size of the back to add ‘!’, it will be forced to zoom in according to the given width.

Image added watermark:

Suppose the watermark icon named logo.gif is added to the lower right corner of the original image (src.jpg), and the lower edge of the watermark is 10 pixels from the original picture and the right edge is 5 pixels from the original picture. Use the following commands:

Convert src.jpg logo.gif -gravity Southeast -geometry +5+10 -composite dest.jpg

For example, if www.dianwoda.com is added to the picture as watermark, the order is as follows:

Convert src.jpg -gravity Southeast -fill black -pointsize 16 -draw " text 5,5 text;

The commonly used parameter use Description:

-crop width x high + starting abscissa + starting ordinate: clipping graph

-resize wide x high!: change the size, if the exclamation mark is used, that the visual proportion is not retained, and the size matches the given width and height. If only a given width or height, such as “wide x” or “x high”, is the same as the effect of “x high” and “wide x high”), it is proportional to the known parameter as the base. Size.

-colors color number: set the number of colors used in the picture. If you generate PNG or GIF picture, you should specify this parameter.

-quality quality: set JPEG picture output quality, recommended 80, this command is only used for the output format is JPG, should not be omitted, the default quality is 95, the generated picture is too large.

+profile " *&quot:: the picture does not store Exif information, it must be used, otherwise the generated image is too large.

3. application in Java code

/ * * * * *

*

* a series of operations uploaded by @Description: images, including the clipping of pictures and the addition of watermark.

* @author Luzhe

* @param pic original picture

* @param picFileName picture name

* @return void return type

* @throws

* * /

Public void covertImage (File pic, String picFileName) {

String relativePath = " image/license";;;

String path = SystemConst.IMAGE_ROOT;

/ / suffix name

String suffix = picFileName.substring (picFileName.lastIndexOf (“.”).

+ 1);

/ / new file name

String newFileName = UUID.randomUUID ().ToString ();

/ / the location of the new picture saved

File savePath = new File (path, relativePath + " /"

+ newFileName + "." + suffix);

Try {

BufferedImage originImg = ImageIO.read (PIC);

/ / download pictures to the specified location

ImageIO.write (originImg, suffix, savePath);

MagickConvertImpl magick = new MagickConvertImpl ();

String root = getSession ().GetServletContext ().GetRealPath (" /");

/ / watermark picture

File press = new File (root, " images/press/press.png&quot);

/ / watermark path

String pressPath = press.getAbsolutePath ().Replace (" \\" " /&quot);

String srcPath = savePath.getCanonicalPath ().Replace (" \\" " /&quot);

String destPath = srcPath;

/ / add clipping command

Magick.setCommand (" convert");

/ / add the compressed size

Magick.resize (" 550×412");

Magick.arg (srcPath);

Magick.arg (destPath);

String[] positions = new String[] {" NorthWest" " North"

" NorthEast" " West" " Center" " East" " SouthWest" " "

" SouthEast"};

/ / here, positions refers to (upper, lower, left, right, middle, left, right, left, right, bottom).

For (int i = 0; I < positions.length; i++) {

/ / add watermark command

Magick.setCommand (" composite");

Magick.arg (pressPath);

Magick.arg (srcPath);

Magick.gravity (positions[i]);

Magick.arg (destPath);

}

MagickResult result = new MagickResult ();

/ / start operation of the command

Magick.execute (result);

Return;

} catch (IOException E) {

Log.error (" save picture error: " E);

}

}

Public Boolean execute (MagickResult result) {

Process process;

List

CommandLines = new ArrayList

() ();

If (result = = null) {

Result = new MagickResult ();

}

Try {

CommandLines.add (getCommandLine ());

For (String commandLine: commandLines) {

Log.info (" [ImageMagick] execution command: [" + commandLine + "]");

Process = Runtime.getRuntime ().Exec (commandLine);

AbstractMagickCommand.getCommandMessage

(result.getStdOut () (), process.getInputStream ());

AbstractMagickCommand.getCommandMessage

(result.getStdErr () (), process.getErrorStream ());

Process.waitFor ();

Process.destroy ();

Result.setExitValue (process.exitValue ());

If (! Result.isOk ()) {

Error occurred when log.warn (" [ImageMagick]) was executed; ");

For (String line: result.getStdErr ()) {

Log.warn (" [ImageMagick] command error: [" + line + "]");

}

Return false;

}

}

} catch (IOException IOE) {

Log.warn (ioe.getMessage (), IOE);

Return false;

} catch (InterruptedException Ex) {

}

Return result.isOk ();

}

Note: if it is running under windows, you need to configure the path of the ImageMagick, add in the environment variable path, or add it in the configuration file. Of course, imageMagic has many other functional commands. Here are just some of the commonly used ones.

Using IntentService to solve the priority ranking problem of rider APP message reminder mechanism

The latest edition of point rider APP has made specifications and optimizations for new order message alerts, order information modification, new robbing orders and other sound and brake alerts, adding message alerts (including sound and vibration alerts) priority mechanism, that is, a higher priority sound has a lower priority in the play. The lower priority sounds are not played in the playback queue; the lower priority sound is inserted into the playqueue in the playing process, and the higher priority sound is played after the lower priority sound play. This paper introduces how to execute time-consuming tasks (audio playback, etc.) more safely and efficiently, and how to perform tasks in task queue in an orderly way.

1. how to play audio files?

Here’s " how to play the audio file " it doesn’t mean what API zone is played, but when the Android client APP is limited in the application memory (the specific APP is allocated in memory with the Android system version, the mobile vendor’s customization of the Android system, the handset hardware configuration, etc.) how to ensure that it is played. In the process of audio files, as far as possible, no loss of application performance will result in significant performance problems such as ANR and Crash.

First, paste the three kinds of audio files that are introduced in the later version, which are common utility code, and do not like to spray them.

Package audio.rider.dwd.com.audioplayer.util;

Import android.content.Context;

Import android.media.MediaPlayer;

Import android.util.Log;

Import audio.rider.dwd.com.audioplayer.R;

/ * * * * *

* Created by WangChunelei on 16/10/28.

* audio playback tool class

* * /

Public class AudioManager {

Private static final String TAG = " AudioManager"

Private static AudioManager Singleton;

/ * the audio priority is being played /

Private int audioPriority;

/ * callback object * /

Private OnAudioChangeListener onAudioChangeListener;

/ * the number of current audio playback * /

Private int currentRepeatIndex = 0;

/ * sound player object * /

Private MediaPlayer mediaPlayer = null;

/ * frequency of sound / * / * / * / * / *

Int audioRepeatCount = 0;

Private AudioManager () {

}

Public static AudioManager getInstance () {

If (singleton = = null) {

Synchronized (AudioManager.class) {

If (singleton = = null) {

Singleton = new AudioManager ();

}

}

}

Return Singleton;

}

/ * * * * *

* playing audio files

*

* @param context

* @param audioPriority reminding priority

* * /

Public void playAudio (Context context, int audioPriority) {

This.audioPriority = audioPriority;

This.currentRepeatIndex = 0;

This.audioRepeatCount = 0;

Android.media.AudioManager audioManager = (android.media.AudioManager) context.getSystemService (Context.AUDIO_SERVICE);

Int current = audioManager.getStreamVolume (android.media.AudioManager.STREAM_MUSIC);

Int maxcurrent = audioManager.getStreamMaxVolume (android.media.AudioManager.STREAM_MUSIC);

While (current < maxcurrent) {

AudioManager.adjustStreamVolume (android.media.AudioManager.STREAM_MUSIC, android.media.AudioManager.ADJUST_RAISE, 0);

Current = audioManager.getStreamVolume (android.media.AudioManager.STREAM_MUSIC);

}

Switch (audioPriority) {

Case 1:// new order message reminder – audio playback 2 times

MediaPlayer = MediaPlayer.create (context, R.raw.neworder);

AudioRepeatCount = 2;

Break;

Case 2:// order was modified – audio playback 3 times

MediaPlayer = MediaPlayer.create (context, R.raw.updateorder);

AudioRepeatCount = 3;

Break;

Case 3:// order was cancelled – audio playback 3 times

MediaPlayer = MediaPlayer.create (context, R.raw.cancelorder);

AudioRepeatCount = 3;

Break;

Default:

Break;

}

If (onAudioChangeListener! = null) {

OnAudioChangeListener.onAudioStartPlaying ();

}

/ / / / audio file playback after the end of the playback

MediaPlayer.setOnCompletionListener (New MediaPlayer.OnCompletionListener () {

@Override

Public void onCompletion (MediaPlayer MP) {

Log.e (TAG, " currentThread:" + Thread.currentThread ().GetName ());

Try {

/ / play the specified number of audio files

If (currentRepeatIndex < audioRepeatCount – 1) {

MediaPlayer.start ();

CurrentRepeatIndex++;

} else {

/ / playback completion

If (onAudioChangeListener! = null) {

OnAudioChangeListener.onAudioFinished ();

}

}

} catch (Exception E) {

}

}

});

MediaPlayer.start ();

}

/ * * * * *

* get the type of audio file that is playing

*

* @return

* * /

Private int getPlayingAudioType () {

Return audioPriority;

}

/ * * * * *

* setting the state switch listener

*

* @param onAudioChangeListener

* * /

Public void setOnAudioChangeListener (OnAudioChangeListener onAudioChangeListener) {

This.onAudioChangeListener = onAudioChangeListener;

}

/ * * * * *

* the callback of the state switching during the audio file playback

* * /

Public interface OnAudioChangeListener {

/ / start playing audio files

Void onAudioStartPlaying ();

/ / playback completion

Void onAudioFinished ();

}

}

1. main threads perform message reminder tasks

The main thread of the Android system is also called the UI thread. In general, in the UI thread, most of the work is to deal with the UI change, and the time consuming task is not put on the UI thread. Otherwise, it is easy to produce the performance problems such as UI carton, ANR and so on. It has a serious impact on the fluency of the application.

Then the question arises: does the task of playing circular voice in the main thread cause the application of carton, resulting in loss of performance and fluency?

Adding a click event to Activity and directly calling the method can loop the audio file of type 1.

In fact, the use of direct use does not have a significant impact on performance and fluency. Does it mean that the work of playing audio files is not placed on the main thread on the underlying implementation? When we look at the start method of MediaPlayer, we can easily turn to the following lines of code:

As you can see clearly from the code, the bottom is on the native layer when the audio file is played, that is, the C/C++ layer, because the related hardware devices need to be invoked and the load device driver is required to play the audio file.

The result is that the next play will be executed immediately after the end of the sound play. If the current requirement is changed to: play the next broadcast after each playoff interval 2S, is there still no problem with this method?

The easiest way to think is to let threads sleep 2S.

Since the thread is dormant, the work must not be placed on the main thread, because the application of the thread in the process of the thread dormancy can not do any operation directly. The way to solve the problem is to customize child threads to process the playback audio and sleep interval.

2. new Thread executes message alerts

Increase the thread sleep time in the code that listens to the voice in the above code and plays the next sound. The code screenshot is as follows:

Then a new Thread class is created, and the method of playing the sound is called in run (). The code in Thread is as follows:

Create an instance of the thread in Activity and call the start method to open the child thread. Soon after running, UI will also be Caton directly after the 2 seconds of the end of the sound play. In fact, by looking at the log, you can see that the onCompletion callback of MediaPlayer is directly done on the main thread.

Then we need to change the implementation of the sound loop play, and the way the for loop +Thread dormancy can also be easy to achieve, the part of the code that evolves into the following diagram.

Only this dormant time needs to do a bit of processing, that is, after the execution of mediaPlayer.start () immediately into the thread dormancy stage, the sleep time is the sound of the play long +2s, that is, the sound of the thread is also synchronized dormancy during the play, the sound is finished after the thread still has the rest of the rest of the 2S, and so on. After the time of sleep, it enters the next cycle.

Although there is no impact on the performance and fluency of the application, there are some headaches, such as how to safely exit the thread to reduce memory consumption after the end of the task execution, such as how the implementation solution is brought about by priority sort, although it has not had an impact on the performance and fluency of the application through Thread. Problems such as the problem of task insertion. The problem is sure to be solved, but it is on thin ice. If the thread is used in a slightly improper way, there will be various problems that directly lead to the application of Crash.

Is there a solution to automatically terminate the task at the end of the task, to temporarily insert the task automatically, and not to use too many “minefields” in the process? IntentService is in use.

3. use IntentService to perform message reminder tasks

To do Android development of the Service must be unfamiliar, Service as one of the four components of Android, acting as a component of the role of computing, mainly used in the background processing some tasks, such as the point I reached the rider Android client longitude and latitude upload is Service background processing.

Service handles tasks in the background, but " backstage " not equal to " asynchronous " and Service default is carried out on the UI thread, so for some time-consuming, consumable work, if it needs to be processed in Service, it also needs to be handled separately in Service.

IntentService is a subclass of Service, but it is quite different from Service.

1.IntentService creates an independent worker thread by default to handle tasks, and has little impact on application performance.

2.IntentService has a &quot that the task handles in turn; queues for " functions (in fact, the Looper polling and thread wake-up mechanism), can execute tasks in the task queue in turn.

3. Service is automatically destroyed after the mission is completed. There is no way to worry about the effect of empty task Service on application performance.

The use of IntentService is similar to that of ordinary Service, such as the need to declare in AndroidManifest.xml, and all can be started in the way of startService. However, IntentService needs a default constructor, and the execution of the task is in onHandleInten.

Android custom controls to achieve color progressive circular progress

First glance, the effect of custom controls is shown below.

The effect of this control is still very common, but it is limited to the Android system which does not provide such effect control, so it can only enrich its own clothing.

In the Android project, some of the Android system source controls need to be implemented because of the requirements of the product requirements or the requirements of the UI effect diagram. So custom controls are required to achieve the relevant effects. Therefore, custom controls are also a basic work for the development of Android. This article introduces the relevant process of custom controls based on the inheritance of View and the use of Canvas to draw graphics.

1. customize CircleProgressBar, inherit View, and implement the constructor of the response.

The code is as follows:

/ * * * * *

* Created by WangChunLei

* * /

Public class GradientProgressBar extends View {

Public GradientProgressBar (Context context) {

Super (context);

Init ();

}

Public GradientProgressBar (Context context, AttributeSet attrs) {

Super (context, attrs);

Init ();

}

Public GradientProgressBar (Context context, AttributeSet attrs, int defStyleAttr) {

Super (context, attrs, defStyleAttr);

Init ();

}

}

The init method is the initialization method for the related brush. The init method code is as follows:

Private void init () {

BackCirclePaint = new Paint ();

BackCirclePaint.setStyle (Paint.Style.STROKE);

BackCirclePaint.setAntiAlias (true);

BackCirclePaint.setColor (Color.LTGRAY);

BackCirclePaint.setStrokeWidth (circleBorderWidth);

/ / backCirclePaint.setMaskFilter (New BlurMaskFilter (20, BlurMaskFilter.Blur.OUTER));

GradientCirclePaint = new Paint ();

GradientCirclePaint.setStyle (Paint.Style.STROKE);

GradientCirclePaint.setAntiAlias (true);

GradientCirclePaint.setColor (Color.LTGRAY);

GradientCirclePaint.setStrokeWidth (circleBorderWidth);

LinePaint = new Paint ();

LinePaint.setColor (Color.WHITE);

LinePaint.setStrokeWidth (5);

TextPaint = new Paint ();

TextPaint.setAntiAlias (true);

TextPaint.setTextSize (textSize);

TextPaint.setColor (Color.BLACK);

}

2. the width and height of the control control -onMeasure

OnMeasure is the first step of custom control. The purpose is to measure the width and height of the control. The code of the onMeasure method is as follows:

@Override

Protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {

Int measureWidth = MeasureSpec.getSize (widthMeasureSpec);

Int measureHeight = MeasureSpec.getSize (heightMeasureSpec);

SetMeasuredDimension (Math.min (measureWidth, measureHeight), Math.min (measureWidth, measureHeight));

}

After the onMeasure code is posted, it is estimated that it is rarely seen as simple as the measurement process such a simple onMeasure, do not mind, the interested colleagues can refine this measurement process, the different measurement modes are processed and measured separately, so that the control is better and more perfect. In the onMeasure method, we get the desired width and height separately and take the smaller size as the width and height of the control.

3., in turn, draw different components of the control.

Because the control is directly inherited from the View, it does not need to reprocess the onLayout method, which is one of the differences between the custom View and the custom ViewGroup, but the inheritance of the ViewGroup does not necessarily have to rewrite the onMeasure.

To achieve the effect as shown, we need to implement the following steps in turn.

(1) draw a gray hollow ring

(2) draw a ring of color gradient

(3) draw the white lines divided on the ring

(4) draw percentage words and so on.

If the content of the rendering process is intersecting with the content previously drawn, the content that is drawn later will cover the content before it is drawn. According to the steps mentioned above, the following member variables will be generated during the rendering process.

/ * circular arc linewidth * /

Private float circleBorderWidth = TypedValue.applyDimension (TypedValue.COMPLEX_UNIT_DIP, 20, getResources ().GetDisplayMetrics ());

/ * internal margin * /

Private float circlePadding = TypedValue.applyDimension (TypedValue.COMPLEX_UNIT_DIP, 20, getResources ().GetDisplayMetrics ());

/ * font size * /

Private float textSize = TypedValue.applyDimension (TypedValue.COMPLEX_UNIT_SP, 50, getResources ().GetDisplayMetrics ());

/ * to draw a circumference brush /

Private Paint backCirclePaint;

/ * a brush drawing a circumferential white line

Private Paint linePaint;

/ *

Private Paint textPaint;

/ * percentage * / /

Private int percent = 0;

/ * the gradient of the circle color array * /

Private int[] gradientColorArray = new int[]{Color.GREEN, Color.parseColor (" #fe751a&quot); Color.parseColor (" #13be23"); "

Private Paint gradientCirclePaint;

3.1 draw a gray hollow ring

The code is as follows:

//1. draws a gray background circle

Canvas.drawArc (

New RectF (circlePadding * 2, circlePadding * 2,

GetMeasuredWidth () – circlePadding * 2, getMeasuredHeight () – circlePadding * 2, -90, 360, false, backCirclePaint);

Among them, -90 is the initial angle to draw the arc, and the 360 is the angle drawn by the circle, that is, sweepAngle..

3.2 draw a ring of color gradient

//2. draws the color gradient circle

LinearGradient linearGradient = new LinearGradient (circlePadding, circlePadding).

GetMeasuredWidth () – circlePadding,

GetMeasuredHeight () – circlePadding,

GradientColorArray, null, Shader.TileMode.MIRROR);

GradientCirclePaint.setShader (linearGradient);

GradientCirclePaint.setShadowLayer (10, 10, 10, Color.RED);

Canvas.drawArc (

New RectF (circlePadding * 2, circlePadding * 2,

GetMeasuredWidth () – circlePadding * 2, getMeasuredHeight () – circlePadding * 2, -90, (float) (percent / 100) * 360, false, gradientCirclePaint);

Among them, linearGradient is the shadow of Paint, which needs to be set for the color gradient effect of the arc. The application frequency in the daily development is not high, but it is true that it can achieve a very ideal color gradient effect.

3.3 draw the white lines divided on the ring

When drawing the white lines on the arc, some simple operations are needed, such as the starting coordinates of the lines startX, the startY and the terminating coordinates of the lines, stopX, stopY, etc., which are easily calculated using a simple trigonometric function. In the effect, the circular arc is divided into 100 points with white lines. Each class is 1, which can meet the percentage of the int type and the proportion of the effect map.

/ / / radius

Float radius = (getMeasuredWidth () – circlePadding * 3) / 2;

//X axis center point coordinates

Int centerX = getMeasuredWidth () / 2;

//3. draws 100 line segments to cut into hollow arcs

For (float I = 0; I < 360; I + = 3.6) {

Double rad = I * Math.PI / 180;

Float startX = (float) (centerX + (radius circleBorderWidth) * Math.sin (RAD));

Float startY = (float) (centerX + (radius circleBorderWidth) * Math.cos (RAD));

Float stopX = (float) (centerX + radius * Math.sin (RAD) + 1);

Float stopY = (float) (centerX + radius * Math.cos (RAD) + 1);

Canvas.drawLine (startX, startY, stopX, stopY, linePaint);

}

3.4 draw percentage text and finally draw percentage text. In order to draw text, in order to keep the center point of the text and the origin of the arc, it is necessary to measure the width and height of the text first, and then carry out some simple calculations. The principle is no longer described. I believe that everyone is better than me.

//4. drawing text

Float textWidth = textPaint.measureText (percent + "%");

Int textHeight = (int) (Math.ceil (textPaint.getFontMetrics ().Descent – textPaint.getFontMetrics ().Ascent) + 2);

Canvas.drawText (percent + "%" centerX textWidth / 2, centerX + textHeight / 4, textPaint);

Finally, a common method is changed to change the percentage of display. The code is as follows:

/ * * * * *

* setting percentage

*

* @param percent

* * /

Public void setPercent (int percent) {

If (percent < 0) {

Percent = 0;

} else if (percent > 100) {

Percent = 100;

}

This.percent = percent;

Invalidate ();

}

At this point, all drawing processes are outlined, and 130 lines of code can achieve very cool effects. Finally, paste the complete code of the project for students who are too lazy to see the implementation process, O (O) ha ha.

Package com.example.myview;

Import android.content.Context;

Import android.graphics.*;

Import android.util.AttributeSet;

Import android.util.TypedValue;

Import android.view.View;

/ * * * * *

* Created by WangChunLei

* * /

Public class GradientProgressBar extends View {

/ * circular arc linewidth * /

Private float circleBorderWidth = TypedValue.applyDimension (TypedValue.COMPLEX_UNIT_DIP, 20, getResources ().GetDisplayMetrics ());

/ * internal margin * /

Private float circlePadding = TypedValue.applyDimension (TypedValue.COMPLEX_UNIT_DIP, 20, getResources ().GetDisplayMetrics ());

/ * font size * /

Private float textSize = TypedValue.applyDimension (TypedValue.COMPLEX_UNIT_SP, 50, getResources ().GetDisplayMetrics ());

/ * to draw a circumference brush /

Private Paint backCirclePaint;

/ * a brush drawing a circumferential white line

Private Paint linePaint;

/ *

Private Paint textPaint;

/ * percentage * / /

Private int percent = 0;

/ * the gradient of the circle color array * /

Private int[] gradientColorArray = new int[]{Color.GREEN, Color.parseColor (" #fe751a&quot); Color.parseColor (" #13be23"); "

Private Paint gradientCirclePaint;

Public GradientProgressBar (Context context) {

Super (context);

Init ();

}

Public GradientProgressBar (Context context, AttributeSet attrs) {

Super (context, attrs);

Init ();

}

Public GradientProgressBar (Context context, AttributeSet attrs, int defStyleAttr) {

Super (context, attrs, defStyleAttr);

Init ();

}

Private void init () {

BackCirclePaint = new Paint ();

BackCirclePaint.setStyle (Paint.Style.STROKE);

BackCirclePaint.setAntiAlias (true);

BackCirclePaint.setColor (Color.LTGRAY);

BackCirclePaint.setStrokeWidth (circleBorderWidth);

/ / backCirclePaint.setMaskFilter (New BlurMaskFilter (20, BlurMaskFilter.Blur.OUTER));

GradientCirclePaint = new Paint ();

Web optimization training camp, web page speed 50 times

Preface

We will use a complete example to optimize loading, rendering and other experiences step by step.

start

First, let’s look at the file composition of the project

This includes a basic web page element, JS (React App), CSS, and pictures.

Related resources see https://github.com/joesonw/web-accelerate-example

Let’s take a look at the whole page of serve first.

Server.js

‘use strict’;

Const FS = require (‘fs’);

Const path = require (‘path’);

Const koa = require (‘koa’);

Const app = koa ();

App.use (function* (next) {)

Const file = this.path.slice (1)’index.html’;

Try {

Const content = yield CB => fs.readFile (path.resolve (‘./dist’, file), CB);

This.body = content;

This.type = path.extname (file).Slice (1);

This.status = 200;

} catch (E) {

This.status = 404;

}

Yield next;

});

App.listen (process.env.PORT 3000);

This code is simply a forwarding of the files in the dist directory.

When you open the web page, you can see the related load.

As we can see, the whole app.js is 277kb, and in the case of the analog 3G network (blue frame), each load takes 999ms, and the download costs 911ms (red frame).

Next we will gradually optimize, and then compare the results every time.

Optimization (1) – – 304

The most common one in Web loading optimization is 304 Not Modified, the specific mechanism is the browser launch request, the headers contains If-Modified-Since, (such as without caching, the header field), the server compares the time of the final modification of the file on the hard disk (or in the memory), if the result is less than or equal to the request time, then return 304. otherwise, It returns 200 and adds the Last-Modified field, telling the client that the next request can try to ask whether there is a cache.

The specific code is as follows:

App.use (function* () {()

Const file = path.resolve (__dirname, path.resolve (‘dist’, this.path.slice (1)’index.html’));

Const headers = this.headers;

Let ifLastModified = this.headers[‘if-modified-since’];

If (ifLastModified) {

IfLastModified = new Date (ifLastModified);

}

Try {

Const stat = yield CB => fs.stat (file, CB);

Const now = Date.now ();

If (ifLastModified & &

File! = = path.resolve (__dirname, path.resolve (‘dist/index.html’)) {

If (ifLastModified > = stat.mtime) {

This.status = 304;

Return;

}

}

Console.log (file)

Const content = yield CB => fs.readFile (file, CB);

This.body = content;

This.type = path.extname (file).Slice (1);

This.status = 200;

This.set (‘Last-Modified’, stat.mtime);

} catch (E) {

This.status = 404;

}

});

(simulation of the actual situation, the home page will be dynamically generated, add some ads, tracking or personalized data, index.html is not cached).

Final effect:

We can see that the download time is 2ms, which can be almost ignored (only HTTP Headers), and the total load time is only 120ms, and 869ms. is a lot less 869ms. than before.

But, are we satisfied?

Optimization (two) — package separately

We can notice that we pack up only one JS file in the end, when the dependency is much changed (in this case only react and react-dom, each modification causes the entire JS file to be rerequested. So we want to extract different library (even the common code modules within the project).

We first need to create a webpack.vendors.config.js to build these library, or vendor..

Const path = require (‘path’);

Const WebpackCleanupPlugin = require (‘webpack-cleanup-plugin’);

Const HtmlWebpackPlugin = require (‘html-webpack-plugin’);

Const webpack = require (‘webpack’);

Const ExtractTextPlugin = require (" extract-text-webpack-plugin");

Module.exports = {{

Plugins: [

New webpack.DefinePlugin ({

‘process.env’: {

NODE_ENV:’" production" ‘,

},

}),

New webpack.optimize.OccurenceOrderPlugin (),

New webpack.optimize.UglifyJsPlugin ({

Compress: {

Warnings: false,

Screw_ie8: true,

Drop_console: true,

Drop_debugger: true,

},

}),

New webpack.DllPlugin ({

Path: path.resolve (__dirname,’dist/vendor/[name]-manifest.json’),

Name:'[name]’,

Context: ‘.’,

}),

]

Devtool:’hidden-source-map’,

Entry: {

‘react’: [‘react’,’react-dom’],

},

Output: {

Path: path.resolve (__dirname,’dist/vendor’),

Filename:'[name].js’,

Library:'[name]’,

},

};

Be aware

Entry: {

‘react’: [‘react’,’react-dom’],

},

It means that we can package the same type of package into a JS file.

Of course, we also need to make some modifications to webpack.production.js.

Const DLLs = fs.readdirSync (path.resolve (__dirname,’dist/vendor/’))

.filter (file => path.extname (file) = = =’.js’)

.map (file => path.basename (file,’.js’))

Const dllReferencePlugins = DLLs

.map (DLL =>

New webpack.DllReferencePlugin ({

Context: ‘.’,

Manifest: require (`./dist/vendor/${dll}-manifest.json`),

})

);

Module.exports = {{

Plugins: dllReferencePlugins.concat (

])

}

Here, we will automatically scan the files under the vendor directory and load all the vendor automatically.

In this way, we implemented subpackage loading (and some details were revised, including index.html, see GitHub, Step-2 branch).

The result is pretty good. App.js only needs more than 400 ms for loading alone, which is faster than at least half of all loading.

For general types of websites, the optimization has achieved very good results, but for large websites, we can still do a lot.

Optimization (three) – forced caching

We can note that optimization, one 304 of the request still takes more than 100 milliseconds, for large sites, and a lot of resources, this is still a very small expense. So can we save this? The answer is yes.

In the browser cache, there is a special field. Expires, which can specify the expiration time of the file until that moment, and the browser will not reinitiate the request, but read directly from the local cache.

However, it still needs to be requested every other time. How should we do it? The answer is, set extra long cache time, for example, 10 years. But then we can’t update anything. How can we use such features and easily update it.

We can add the hash feature value to the file name so that it can be reloaded only when the content of the file is changed, and it is suitable for distributed CDN, non overlay release, which can make it use the new resource in the case that the reference page (the front page) has been changed (the current server has been published), and the access is not available. When the server is published, it will still refer to the old resources, so that the Publication no longer needs to stay up late.

The details of the changes are seen in Git branch step-3.

Implementation results: you can see from the blue box that the cache has already taken effect, and the overall read time is only 20 milliseconds.

From the original 1000 milliseconds to the current 20 milliseconds, the simple three steps can make your webpage load 50 times faster.

Extended reading

1. in actual production, we usually see the loaded CDN domain name. Why?

This is because a large web site, the request will bring a lot of Cookie, some even close to the 1KB, and the 100 Picture loading, is the full 100KB. through the third party domain name (different from the current domain name), we can save a lot of unnecessary request head, Cookie head. Also to achieve the speed of the purpose.

2. another situation is that resources are distributed on different servers.

This is because browsers limit the number of concurrent downloads of resources under the same domain name.

The use of different resource servers can avoid this restriction and increase the number of downloads. However, the same cache hit rate is the same problem, so it also needs to store the data related to the user’s cache.

3. other methods

With the rapid development of technology, there are still many technologies that can enhance the experience of end-users.

BigPipe + Server-Side Rendering speeds up home page loading speed.

Goole AMP

HTTP/2

The past and present of JavaScript’s prototype and prototype chain (two)

3.1. Archetypal objects

In the last article, we talked about the prototype attribute, which points to an object, and the object is used to include attributes and methods that can be shared by all instances of a particular type. In the standard, we call this object a prototype object. Prototyping objects are generated by a set of specific rules when creating a new function.

Since there is an attribute of prototype, why did the browser in the last article capture __proto__? According to the introduction in the ECMA-262 fifth edition, the pointer inside the instance is clearly called [[Prototype]], although there is no standard way to access the pointer, but Firefox, Safari, and Chrome support an attribute __proto__ on each object, so the __proto__ you see is actually a access interface of the browser’s own implementation. It’s not the standard set. But in fact, it is better to follow the browser’s design.

Having said so much, ask a question: who is the connection between __proto__ and whom? I can think about it well.

Although [[Prototype]] can not be accessed, the isPrototypeof () method can be used to determine whether there is a relationship between objects, or getPrototypeof () can be used to get the value of the [[Prototype]].

Since the properties of the prototype object can also be accessed in the instantiated object, then what is the way to determine whether the attributes of the access are in the instantiated object or in the prototype object? The answer is isOwnProperty ().

The for-in loop traverses all properties that can be accessed and enumerated by object, whether in the instance or in the prototype. In the 6.2 section of JavaScript advanced programming (Third Edition), there is such a redundancy:

The instance attribute that shields the properties of the prototype (which is about to mark [[Enumerble]] as false) will also be returned in the for-in loop. According to the author’s understanding, if you define a property that is the same as the name in the prototype in the instance property and the attribute is enumerated in the prototype, then for-in will still return the property. This is actually a very obvious proposition because for-in finds the property in an instance, and the attribute is enumerable (unless you manually set it to the enumerated).

It is troublesome to enumerate all enumerated attributes one by one. Fortunately, ES5 provides Object.keys () method to get all enumerated attributes. If you want to get all instance properties, you can use Object.getOwnPropertyNames ().

It has been said that the prototype model has shortcomings, and its biggest disadvantage is its shared characteristics, and any one of the attributes in the prototype object can affect all the objects it instantiated, which causes the phenomenon of “seeking the same and saving the difference”. So we will use the following one more.

3.2. Use constructor mode and prototype mode together.

In combination, of course, all the shared attributes are placed in the prototype object, and all the unique attributes are placed in the constructor, so that the true “seek the same and save the difference”. For example:

Function Animal () {

This.name = name;

This.type = type;

This.say = function () {

Console.log (‘I am a ‘+ this.type);

}

}

Animal.prototype = {{

Constructor: Animal;

FeetCount: 0;

Run: function () {

Console.log (‘I can run’);

}

}

Var dog = new Animal (‘WangWang’,’dog’);

Be careful:

Why does Animal.prototype reassign constructor here?

Children’s shoes combined with an article can think about it!!

Can we consider optimizing the code above to reduce the amount of code? The dynamic prototype mode can be used at this time:

Function Animal () {

This.name = name;

This.type = type;

This.say = function () {

Console.log (‘I am a ‘+ this.type);

}

If (typeof this.run! =’function’) {

Animal.prototype.feetCount = 0;

Animal.prototype.run = function () {

Console.log (‘I can run’);

}

}

}

Var dog = new Animal (‘WangWang’,’dog’);

Be careful:

Why can’t we use the font size of the object in the above example when initializing the prototype here?

Children’s shoes can also be thought for themselves!

In the JavaScript advanced programming (Third Edition), two patterns are also introduced to create objects: the parasitic constructor mode and the Durable constructor pattern, and the details can be referred to books.

4, archetypal chain

Presumably here, you should have been able to guess the implementation principle of the prototype chain. ES5 uses the prototype chain as the main way to implement inheritance (because the function does not have a signature). Interface inheritance cannot be implemented in ES5). The basic idea is to use the prototype to make one reference type inherit the properties and methods of another reference type. Let’s improve the last section of the picture 3:

It can be seen that through [[prototype]] attribute, the prototype object of instance, prototype object and prototype object is concatenate. This connection is prototype chain.

The same prototype chain also has two problems: a problem with a reference type value in a + prototype (that is, the problem just in the 3.1 section) + cannot pass parameters to the supertype constructor when creating an instance of a subtype.

Therefore, the commonly used solutions include the following:

4.2. Combination inheritance

Combination inheritance is sometimes referred to as pseudo classical inheritance. The scheme combines the constructor (reference 4.2.1 section) and the prototype chain. Look at the following examples:

Function Species (name, type) {

This.name = name;

This.type = type;

}

Species.prototype.run = function () {

Console.log (‘I can run! “);

}

Function Animal (name, type, age) {

Species.call (this, name, type);

This.age = 0;

}

Animal.prototype = new Species;

Animal.prototype.constructor = Animal;

Animal.prototype.reportAge = function () {

Console.log (‘My age is’ + this.age);

}

Var dog = new Animal (‘WangWang’,’dog’, 11);

Dog.run ();

Dog.reportAge ();

The prototype chain diagram of the code is as follows:

4.2.1, borrowing constructor

Using the constructor (constructor stealing) (sometimes called a forgery object or classic inheritance), the principle is simple, that is, the supertype constructor is called within the subtype constructor. For example:

Function Species () {

This.colors= [‘red’,’green’];

}

Function Animal (type, name) {

Species.call (this);

This.type = type;

This.name = name;

}

Var dog = new Animal (‘dog’,’WangWang’);

Dog.colors.push (‘black’);

Var cat = new Animal (‘cat’,’MiMi’);

Cat.colors.push (‘yellow’);

Because using the call function method, when the Species superclass is instantiated, the this pointer points to the instantiated subclass, which is equivalent to colors as the attribute of the subclass Animal, so each instance’s colors is its own private property. As follows:

Because by using the call method, we can also pass parameters to the superclass.

Function Species (feet) {

This.colors= [‘red’,’green’];

This.feet = feet

}

Function Animal (type, name, feet) {

Species.call (this, feet);

This.type = type;

This.name = name;

}

The problem caused by this method is also the common disease of the constructor – that is, the method cannot be reused, each instance has its own method of an instance, so it is generally used in the above way.

4.3. Other schemes

In addition to the combination of inheritance, there are three methods, such as prototype inheritance, parasitic inheritance, parasitic combination inheritance, and so on. The following three methods are not much used, so no introduction is made, and the details can be referred to “JavaScript advanced program design (Third Edition)”.

5. Summary

Through this article, from the first simplest object to the constructor pattern and the prototype pattern creation object, we can see the strong vitality of the language and become more and more interesting in the continuous optimization. We have also grasped the way of creating objects from these evolutions, and studied the obscure concepts of archetype and prototype chain. A thorough study of a concept is often about the history of its evolution, so we must know the future and never forget it.

6. Reference

[1] JavaScript advanced programming (Third Edition) sixth chapter

[2] MDN

[3] ES5 standard

The past and present of JavaScript’s prototype and prototype chain (1)

You don’t have to be frightened by the name of this feeling. I’m not going to say the history of the prototype. This article just wants to help you understand why the prototype and the prototype chain is a unique language, and other languages (or the programming words I’ve learned) have not seen this concept. It was also the most puzzling puzzle when I switched from C to JavaScript.

1. First from JavaScript to create objects

As we all know, JavaScript is an object oriented language, but there is no concept of class (except the current ES6 standard). Personally feel that ES6 is a new standard encapsulated on ES5, and its essence is ES5. Therefore, mastering ES5 is the essence. There is no concept of class, but there must be the concept of object, and the object of JS is different from other object oriented languages (such as C++). Each object is based on a reference type (such as Array/Date/Function and so on, which belongs to the reference type, with a specific reference to the fifth chapter of the JavaScript advanced programming (Third Edition)) or a custom type.

The most common way to create objects before was (by creating a Object instance):

Var animal = new Object ();

Animal.name =’WangWang’;

Animal.type =’dog’;

Animal.say = function () {

Console.log (‘I am a ‘+ this.type);

}

After that, a method of creating an object literal is presented.

Var Animal= {

Name:’WangWang’,

Type:’dog’,

Say: function () {

Console.log (‘I am a ‘+ this.type);

}

}

First of all, it is clear that an object must contain attributes and methods: name and type are definitely attributes, and say is definitely a method. Second, attributes have corresponding properties inside the browser, which are used by the internal JS engine.

1.1. Talk about the properties in the JS object (Property)

In accordance with the ES5 standard, attributes are a name that we know in the impression, a value, similar to the form of a key pair, in fact, there is a large article inside the browser.

Attributes are divided into data attributes (‘Data Property’) and accessor properties (Accessor Property). The name and type that have just been defined are data attributes, and the basis for distinguishing data attributes and accessor data is that the accessor property has a [[Get]] and [[Set]] method and it does not contain a [[value]] feature (Attribute).

The data attribute contains 4 characteristics: [[configurable]], [[Enumerable]], [[Writable]] and [[Value]].

The accessor property contains 4 properties: [[Configurable]], [[Enumerable]], [[Get]], [[Set]].

Although these features are internal use of browsers, ES5 still provides the interface for us to call:

Object.defineProperty (obj, prop, descriptor);

Object.defineProperties (obj, props);

Object.getOwnPropertyDescriptor (obj, prop);

Object.getOwnPropertyDescriptors (obj);

Take an example (in the Chrome console):

> Object.getOwnPropertyDescriptor (Person, " name")

> Object {value: " WangWang" writable: true, enumerable: true, configurable: true}

More details of these 4 API (such as compatibility) can be used as reference: MDN

2. Create the advance of the JS object

Although the Object constructor or object literal can be used to create a single object, it is obvious that there is a clear flaw: this method of mixing object creation and object instantiation directly leads to code cannot be reused and a heap of repeated code will be generated, so to solve this problem A new way of creating objects — factory mode has been created. This form begins to approach the instantiation of classes and objects in the C++ language, and is closer to the actual code development.

2.1. Factory model

A very image of the name, as soon as we hear the name, we know that there is a factory at that time. As long as we provide the raw materials, we can use the mold of the factory to help us create the objects we want (that is, the instantiation process).

Because ES5 is unable to create classes, you can only use functions to encapsulate the details of creating objects with specific interfaces. For example:

Function createAnimal (name, type) {

Var o = new Object ();

O.name = name;

O.type = type;

O.say = function () {

Console.log (‘I am a ‘+ this.type);

}

Return o;

}

Var dog = createAnimal (‘WangWang’,’dog’);

Although this approach solves the problem of object instantiation code repetition, it does not solve the problem of object recognition (that is, the object created in this way can’t know its type, for example, the object created by the second previous methods can know that the type of its object is Person). So there is another way to create objects.

2.2, constructor pattern

Constructors are a basic concept in the C++ language, whose function is to initialize calls after instantiating an object, and to perform some replication operations, which can be considered as an initialization function. Similarly, the constructor used by JS is different from C++ in nature, but its essence is the same. JS provides some native constructors such as Object/Array/String, etc., and can also create custom ones. For example:

Function Animal (name, type) {

This.name = name;

This.type = type;

This.say = function () {

Console.log (‘I am a ‘+ this.type);

}

}

Var dog = new Animal (‘WangWang’,’dog’);

This constructor has the following three features:

There is no explicit creation of objects

Assign attributes and methods directly to the this object

No return statement

In performing new operations, you will experience the following 4 steps:

Create an object

Assign the scope of the constructor to the new object (so the this pointer points to the new object).

Execute the code in the constructor

Return a new object

At this time dog is an instance of Animal. According to the tradition of the C++ language, each instance must have an attribute called constructor, and JS is the same, and the constructor attribute of the instance in JS points to the Animal constructor.

The first three methods create the same object, so take one and compare it with factory mode.

It can be seen that the constructor method is indeed more than one attribute, and why these attributes are concentrated in __proto__ is exactly what we should mention later.

So we can identify the type of the object through the constructor attribute (for example, the Animal type in this example), that is, use instanceof to verify.

Of course, using the constructor is not perfect, the main problem with using the constructor is that each method is created in each instance, that is, when we create the Animal object, the method inside is actually an instance of the Function object, that is, the same as:

This.say = new Function (console.log (‘I am a ‘+ this.type);

This leads to the creation of multiple instances of multiple function objects, which obviously increases memory consumption, and in order to solve this problem, we introduce the prototype mode.

3, prototype model

In Figure 1, we have found that each object, whatever the method is created, has a __proto__ attribute, which is the key to the connection of the prototype chain. In the last section, we have 4 steps to perform the operation of the new, of which second steps are based on the code. It is an assignment operation, that is, dog.__proto__ = Animal.prototype, which can be seen through console printing:

The way to create prototype patterns is to adopt such a form:

Function Animal () {}

Animal.prototype.name =’WangWang’;

Animal.prototype.type =’dog’;

Animal.prototype.say = function () {

Console.log (‘I am a ‘+ this.type);

};

Var dog = new Animal ();

The difference between prototype mode and constructor mode can be seen in the following diagram:

Constructor pattern:

Prototype mode:

From the above two pictures, we can see the advantages and disadvantages of the prototype, and how to improve it. Can the integration of the two make full use of the advantages of the two? If you think so, that means you are right. This is the 3.2 subsection.

In addition to the prototype assignment operation, we prefer to use object literal or new keyword to manipulate the prototype. But the use of object literal or new key words has a very important knowledge point: whether using object literal or new keyword, it is to create a new object to replace the original prototype object.

Is it abstract? A picture to tell you the truth:

Code:

Function Animal () {}

Animal.prototype = {{

Name:’WangWang’,

Type:’dog’,

Say: function () {

Console.log (‘I am a ‘+ this.type);

}

}

Var dog = new Animal ();

Or:

Function Species () {

This.name =’WangWang’;

This.type =’dog’;

This.say = function () {

Console.log (‘I am a ‘+ this.type);

};

}

Function Animal () {}

Animal.prototype = new Species ();

Var dog = new Animal ();

The prototype pattern diagrams of the two ones are illustrated.

So precisely because of this overridden effect, when you use this method, you must pay attention to whether the prototype object is still the original prototype object.

Both of the two have the advantages. How do they use the combination? What does the prototype chain have to do with the prototype?

Look at the next chapter: the past and present of the prototype and prototype chain of JavaScript (two).

The front end is from the beginning to the re – entry – Asynchronous

What is asynchronous? That’s about the language of JavaScript.

Born in 1995, JavaScript was designed as a single thread as the script language of browser at that time. That is to say, it can only do one thing at the same time. Why is it like this? Imagine how the browser should respond when the JavaScript is multithreaded, and the user adds content to a node and deletes the node in a thread.

JavaScript solves the complex synchronization problem in browsers with single thread, but a single thread must introduce a concept, that is, the task queue. In a civilized society, there are many demands and few items, so we must queue up. When a task ends, the next task begins. Does it seem perfect, but is there any defect? Yes, we have. For example, when you go to your favorite noodle shop, you find a long queue at the door, but the seats inside are empty. The process of this noodle shop is: customer order, small second and down – customers and small second eyes stare eyes – the kitchen gives the food to the second, the second gives the customer – the customer comes to the table with the food – the end.

Such a process is the most important place is the customer and small eyes stare in the stage, time is wasted on it, so a long queue of people are not satisfied. How should we optimize it?

After discussing with the noodle shop owner, this optimization scheme is given.

Customer order, small second and down – small two give a brand to customers, representing the number of customers – customers sit on the table and start to chat with the mobile phone – the kitchen to the second, the second according to the number to the customer – end.

As soon as the boss heard this well, there were fewer people waiting in line, and the efficiency of the second grade was higher, so he invited me to eat the best beef noodles they had.

This is asynchronous, the time-consuming operation is executed elsewhere, and the result is put back to the queue after execution. In this way, other operations can be done at this time, rather than blocking here. In other words, how does JavaScript realize asynchronous? It’s the callback function.

callback

The callback function is called callback in English, and it is simply to call the callback function after a task is executed, and the callback function can get the result of this task. In the JavaScript world, there is a callback function everywhere. The simplest is the setTimeout method.

SetTimeout (() => alert (‘1000 millisecond after the emergence of me! “), 1000)

The above code is actually waiting for 1000 milliseconds, (=&gt); alert (‘1000 milliseconds) after me! ‘)

It’s the callback function.

The callback function is easy to use and well understood, but how to use multiple asynchronous data together? What is the necessary condition for an asynchronous task? What is the result of another asynchronous task? Some people began to write nested callback, commonly known as the callback of Pyramid.

Fun1 (function (value1) {)

Fun2 (value1, function (Value2) {

Fun3 (Value2, function (value3) {

FUN4 (value3, function (value4) {

/ /…

});

});

});

});

This code is very common in high frequency asynchronous processing such as node. It’s very well written. After a day, you look back at your code, what are you writing about?

At this point, we will embark on a road to find the best solution for asynchronous processing of front-end. As the title says, you think you are getting started. Actually, there is another door in front of you, commonly known as Moore’s law.

EventProxy and publish / subscribe patterns

As the author of the library, Pu Ling

To a great extent,

There is no such thing as deep nesting of callbacks in the world. Jackson Tian

There are no nested callbacks in the world.

. – fengmk2

EventProxy

It is to solve the nesting.

If you want to get data from several addresses asynchronously and process all the data after getting all the data, the simplest way to write a counter in addition to the callback to Pyramid is to write a counter.

Var count = 0;

Var result = {};

$.get (‘http://demo1’, function (data) {

Result.data1 = data;

Count++;

Handle ();

});

$.get (‘http://demo2’, function (data) {

Result.data2 = data;

Count++;

Handle ();

});

$.get (‘http://demo3’, function (data) {

Result.data3 = data;

Count++;

Handle ();

});

Function handle () {

If (count = = = 3) {

/ / follow up operation result

}

}

After the use of EventProxy:

Var proxy = new eventproxy ();

Proxy.all (‘data1_event’,’data2_event’,’data3_event’, function (data1, data2, data3) {

/ / follow up operation result

});

$.get (‘http://demo1’, function (data) {

Proxy.emit (‘data1_event’, data);

});

$.get (‘http://demo2’, function (data) {

Proxy.emit (‘data2_event’, data);

});

$.get (‘http://demo3’, function (data) {

Proxy.emit (‘data3_event’, data);

});

This is a typical event publish / subscribe mode. Let’s throw away the code and start with what is publish / subscribe mode.

Publish / subscribe mode is also called observer mode. The publish / subscribe mode defines a one to many dependency relationship that allows multiple subscribers to listen to a topic object at the same time. The subject object will notify all subscriber objects when their state changes, so that they can update their status automatically.

In a word, your favorite chef’s chef returned home to marry a daughter-in-law, and the beef noodles made by the new chef did not suit your taste, so you called the restaurant every day to ask the old chef to come back. The boss could not bear it any more. Every day he received a similar phone call to get mad and asked me how to deal with it. I said simply, write down the phone call of everyone who wants to eat the beef chef, and tell them that the old chefs come and text them. So the boss’s phone was finally quiet.

The above example of mental retardation is publish / subscribe mode, which is often encountered in our daily life. The boss is the publisher, the customer is the subscriber, the customer subscribes the information which the old chef comes back, when the old chef comes back, the boss releases this news to the customer. What are the benefits of a publish / subscribe pattern? It can decouple logic, publishers need not care about the specific business logic of subscribers, and do not care about how many subscribers, they can deliver messages to subscribers. Subscribers do not have to ask the publisher if they have any news, but they will get the message he wants at the first time.

Back to EventProxy, proxy.emit (‘data1_event’, data) in the above example.

It’s the publisher, proxy.all

The subscriber is the subscriber, but EventProxy’s all API can subscribe to multiple messages at the same time and process all the messages, which is an extension of the common publish / subscribe pattern.

The specific implementation principle of EventProxy comes from the event module of Backbone, and interested GitHub can go to it.

Check it out.

Promise

What is promise? The Chinese meaning of promise is commitment.

I remember that my first contact with promise was in my first angular project, when the code of the project contained many promise.then ().Then ().

I don’t know what it means, I think it’s high-end. At that time, leader and I said, promise is very simple, that is, give you a commitment first, and then finish the next step. It always passes a promise object.

At that time, I naively assumed that promise only had angular, and later discovered that $q in angular was just one of the promise implementations. The entire code base of AngularJS relies heavily on Promise, including the framework and the application code you write with it.

Go back to the point. Many third party libraries have implemented promise, such as when, $q for angular, etc. They follow the same specification: Promises/A+

. Now in the ECMAScript 2015 specification, JavaScript supports native promise (of course, if you want compatibility), use Babel.

The so-called Promise is a container that holds the result of an event that will end in the future (usually an asynchronous operation). A promise may have three states: incomplete, completed, and failed. The state of a promise can never be completed or transferred to completion or failure. It can not be converted backward, and has been completed and failed. At the same time, it is important to note that promise objects are passed between them.

Take a chestnut: you ordered a meal at the noodle shop, and Xiao 2 gave you a meal card. This card is no use for you. You can neither eat nor sell money, but you have to pay for the meal, which is an unfinished state. When the kitchen is ready, Xiao two will take the beef noodle for your meal card, and you get the beef noodles you want to eat. This is the state that has been completed. The beef in the kitchen is sold out, and the second runner comes to apologize to you for letting you change a bowl of noodles or withdraw your money, which is the failure and the handling after failure. Failure has not been directly converted to completion. Do you want to change a bowl or go through the promise process, which is completed and failed and can not be converted to each other.

After knowing the theory of promise, let’s look at the original promise:.

Var promise = new Promise (function func (resolve, reject) {

/ / little two promises to give you a bowl of beef noodles

If (success) {

/ / resolve beef noodles for you

Return resolve (data);

} else {

/ / the kitchen beef is sold out, reject made a mistake for you.

Return reject (data);

}

});

Promise.then (function (data) {)

/ / / success, eat it

Console.log (data);

}, function (ERR) {

/ / failure, I want to refund!

})

The variable promise here is an instance of Promise’s object. If there is no error after the logic process, you can get the beef noodle in the first callback function in then, and if there is a mistake, you will do the wrong processing in the second callback function in the then.

Promise also provides a Promise.all ()

The method is similar to the all of EventProxy, but it returns a promise object. When all promise objects are successful, they will enter the completed state. If one of the promise objects has failed, Promise.all

It will also enter a state of failure. You can view https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/all in detail.

The biggest advantage of promise is that it solves the problem of deep nesting of callbacks through chain calls. It looks elegant and easy to understand and use. But do you think this is all about JavaScript asynchronous programming?

The CO of Generator and TJ

The Chinese meaning of Generator is a generator. In the JavaScript world, functions are not suspended after being executed, only the state of “invoked” and “not invoked”. What happens when the function can be suspended?

Generator is the function that can be suspended. Its essence can be understood as a special data structure. It’s more than a normal function.

Number, *

The number appears between the keyword function and the function name, if it is an anonymous letter.

The front-end rendering accelerates – Big Pipe

Preface

The first screen rendering speed is always a pain point on the front end

From the most open, the direct static resource server returns the resource file directly to the CDN distribution file, then to the server rendering technology. No one is not to get the best experience for the user.

Big Pipe is an accelerated first screen loading technology adopted by Facebook, which can be clearly felt on the front page of Facebook.

brief introduction

It looks as if it’s the same as Ajax

First of all, we need to know that Ajax is just another common HTTP request. The process of a complete HTTP request is

DNS Resolving -> TCP handshake -> HTTP Request -> Server -> Server;

The entire network link has spent quite a lot of time.

Big Pipe only needs to use one connection without additional requests.

The technology behind Big Pipe is not really complex, and the server is passed on to a browser without a closed < body> at this point, the browser will render the DOM that has been received (if there is a CSS, also render). But, at this point, the TCP connection has not been disconnected, < body> the server is not closed yet, the server can follow. Continue to push more DOM to browsers, or even < script>

In this way, the browser can take a page without data (the corresponding data display module to display the load in the load), take the data from the database at the same time, and then push the < script> the tag, and put the data in it. After the browser is received, it can replace the corresponding data.

The difference from the server rendering

Server rendering has a lot of similar places with Big Pipe. It also gets data from the server, fills it into the web DOM and returns to the customer. But the biggest difference is that Big Pipe can return a page to the user before getting the data to reduce the waiting time so as to prevent the data operation from blocking too long, and keeping it all the time. A blank page is given to the user.

The code used in the example of this article

The whole project can be seen as follows: https://github.com/joesonw/bigpipe-example

‘use strict’;

Const koa = require (‘koa’);

Const Readable = require (‘stream’).Readable;

Const co = require (‘co’)

Const app = koa ();

Const sleep = MS => new Promise (R => setTimeout (R, MS));

App.use (function* () {()

Const view = new Readable ();

View._read = () => {};

This.body = view;

This.type =’html’;

This.status = 200;

View.push (`

< html>

< head>

< title> BigPipe Test< /title>

< style>

#loader {

Width: 100px;

Height: 100px;

Border: 1px solid #ccc;

Text-align: center;

Vertical-align: middle;

}

< /style>

< /head>

< body>

< div id=" loader" >

< div id=" content" > Loading< /div>

< /div>

“);

CO (function* () {()

Yield sleep (2000);

View.push (`

< script>

Document.getElementById (‘content’).InnerHTML =’Hello World’;

< /script>

“);

View.push (‘< /body> < /html> “);

View.push (null);

}).Catch (E => {});

});

App.listen (5000);