呆呆窝

  • Home

  • Tags

  • Archives

The Docker Book Learning Note

Posted on 2020-01-03

Chapter1 Introduction

  • Components
    • Client&Server
      • Client talk to Server(Daemon) by API
    • Docker Images
      • “source code” of Container
    • Registries
      • Store the images
    • Docker Container
      • Running/Executing aspect in Docker life cycle

DockerArch

  • Application
    • Make local development and build workflow faster
    • Running stand-alone services and applications consistently across multiple environments
    • Create isolated instances to run tests by Jenkins CI
    • Building and testing complex applications and architectures on a local host

Chapter2 Installation

Chapter3 Getting Start

Commands

Command Option Description
docker info
docker run
-i STDIN open
-t provides an interactive shell
-d detach the container to background
-c run with command
-p network ports Docker publishes at runtime
-P allows us to publish all ports we’ve exposed via EXPOSE instructions in our Dockerfile
–name create container with name
–log-driver control the logging driver used by your daemon and container
–restart always
on-failure:5
docker ps display running container
-a all container
-l last container
-q only list IDs
docker rm remove container
docker rm -f `sudo docker ps -a -q` remove all container
docker start start container
docker attach reattach to the interactive session
must start it first
docker logs access container’s logs
-f monitor logs; similar as tail -f
-t output with timestamp
docker top inspect container’s processes
docker exec running a process inside an running container
-d indicate running background process
docker stats stats info about CPU, memory and network and storage I/O performance and metrics.
docker inspect print more info
-format= template of Go
docker stop
docker port ContainerId get mapped port

Chapter4 Images&Repositories

4.1 What is a Docker image?

4.2-4.4 Commands

Command example Description
docker images
docker pull
docker pull ubuntu:latest
docker pull ubuntu:16.04
docker pull jamtur01/puppet:16.04 username/reponame:tag
docker search
docker login
docker logout
docker commit Create image
SHOULD USE Dockerfile instead
sudo docker commit -m “A new custom image” -a “James Turnbull” 4aab3ce3cb76 jamtur01/apache2:webserver -m: commit message
-a: author
docker history imageId logs about how images created

4.5 Dockerfile

  • Two ways to build images
    • docker commit
    • Dockerfile
  • Dockerfile Workflow
    1. runs a container from the image
    2. runs an instruction and makes a change to the container
    3. runs the equivalent of docker commit to commit a new layer
    4. runs a new container from this new image
    5. repeat 2-4
  • How to build images

    • docker build -t="jamtur01/static_web:v1" .
      • -t: tag
      • .: Dockerfile path
        • local
        • Git repo
    • build cache
      • treat previous layers as a cache
      • --no-cache
      • templating
        • ENV REFRESHED_AT 2019-01-01
        • update the ENV to ensure instructions below it run
  • Instructions

    • FROM
      • specifies an existing base image
    • MAINTAINER
      • MAINTAINER James Turnbull "james@example.com"
    • RUN
      • running the command when the container is being built
      • RUN apt-get install -y nginx
      • RUN [ "apt-get", " install", "-y", "nginx" ]
    • EXPOSE
      • the application in this container will use this specific port on the container
    • CMD
      • specifies the command to run when a container is launched
      • You can only specify one CMD instruction in a Dockerfile
      • docker run image command would override CMD in Dockerfile
      • These 2 are same
        • sudo docker run -i -t jamtur01/static_web /bin/true
        • CMD ["/bin/true"]
    • ENTRYPOINT

      • ENTRYPOINT ["/usr/sbin/nginx"]
      • ENTRYPOINT ["/usr/sbin/nginx", "-g", "daemon off;"]
      • means /usr/sbin/nginx -g "daemon off;"

        1
        2
        3
        4
        5
        # in Dockerfile
        ENTRYPOINT ["/usr/sbin/nginx"]

        # command line launch
        sudo docker run -t -i jamtur01/static_web -g "daemon off;"
      • if we launch the container with right parameter, like -g "daemon off;", it would override the -h. Or it would display the help message by CMD ["-h"]

        1
        2
        ENTRYPOINT ["/usr/sbin/nginx"]
        CMD ["-h"]
      • we can override it by docker run --entrypoint

    • WORKDIR

      • Set working directory for RUN, ENTRYPOINT, CMD

        1
        2
        3
        4
        WORKDIR /opt/webapp/db
        RUN bundle install
        WORKDIR /opt/webapp
        ENTRYPOINT [ "rackup" ]
      • we can override it by docker run -w

    • ENV

      • environment variables during the image build process
      • This new environment variable will be used for any subsequent RUN instructions

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        ENV RVM_PATH /home/rvm/
        RUN gem install unicorn

        # the same as
        RVM_PATH=/home/rvm/ gem install unicorn

        # specify multiple envs
        ENV RVM_PATH=/home/rvm RVM_ARCHFLAGS="-arch i386"

        # can be used in other instructions
        WORKDIR $RVM_PATH

        # These environment variables will also be persisted into any containers created from your image
        echo $RVM_PATH
      • pass environment variables on runtime

        • docker run -e "WEB_PORT=8080"
    • USER

      • specifies a user that the image should be run as

        1
        2
        3
        4
        5
        6
        USER user
        USER user:group
        USER uid
        USER uid:gid
        USER user:gid
        USER uid:group
      • default user is root

      • can be override by docker run -u
    • VOLUMN
      • adds volumes to any container created from the image
      • see Chapter5&Chapter6
    • ADD
      • adds files and directories from our build environment into our image
        • e.g. When installing an application
      • cannot ADD files from outside the build directory or context
      • ADD software.lic /opt/application/software.lic
      • source file can be
        • URL
        • filename
        • directory (should end with /
      • Docker will automatically unpack tar archive (valid archive types include gzip, bzip2, xz)
        • ADD latest.tar.gz /var/www/wordpress/
      • If the destination doesn’t exist, Docker will create the full path
        • with mode 0755, UID 0, GID 0
    • COPY
      • Similar as ADD
      • But doesn’t extract, decompress
    • LABEL
      • Adds metadata to a Docker image
      • LABEL version="1.0" location="NY"
      • can be found in docker inspect
    • STOPSIGNAL
      • sets the system call signal that will be sent to the container when you tell it to stop
    • ARG
      • defines variables that can be passed at build-time via the docker build command
        • ARG webapp_user=user
      • can be overrided by docker build --build-arg webapp_user=bbb. But has to be predefined in Dockerfile
      • Docker predefined ARG variables(we don’t need to define in Dockerfile but pass them by --build-arg
        • HTTP_PROXY, http_proxy
        • HTTPS_PROXY, https_proxy
        • FTP_PROXY, ftp_proxy
        • NO_PROXY, no_proxy
    • SHELL
      • allows the default shell used for the shell form of commands to be overridden
        • default shell on Linux ["/bin/sh", "-c"]
        • default shell on Windows ["cmd", "/S", "/C"]
    • HEALTHCHECK
      • how to test a container to check that it is still working correctly
      • HEALTHCHECK --interval=10s --timeout=1m --retries=5 CMD curl http ://localhost || exit 1
      • We can also check health by docker inspect
        • docker inspect --format '{\{.State.Health.Status}}' static_web
      • There can be only 1 health check
      • Can also disable it
        • HEALTHCHECK NONE
    • ONBUILD

      • adds triggers to images.
      • A trigger is executed when the image is used as the basis of another image
      • it was specified right after the `FROM instruction

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        # basic image Dockerfile
        FROM ubuntu:16.04
        ...
        ONBUILD ADD . /var/www/

        # then we build it
        sudo docker build -t="jamtur01/apache2" .

        # next layer image Dockerfile
        FROM jamtur01/apache2
        ...

        # then we build it
        sudo docker build -t="jamtur01/webapp" .

        ...
        Step 0 : FROM jamtur01/apache2
        # Executing 1 build triggers
        Step onbuild-0 : ADD . /var/www/ # Triggered here

4.6 Pushing images to the Docker Hub

  • Pushing images

    1
    2
    3
    4
    5
    # failed: because Root repositories are managed only by the Docker
    sudo docker push static_web

    # success
    sudo docker push jamtur01/static_web
  • Automated Builds

    • connecting a GitHub or BitBucket repository containing a Dockerfile to the Docker Hub
    • When we push to this repository, an image build will be triggered and a new image created

4.7 Deleting an image

  • Local
    • sudo docker rmi jamtur01/static_web
  • Repo
    • go to web page

4.8 Running your own Docker registry

  • Steps

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # 1. launch a container running version 2.0 of the registry application and bind port 5000 to the local host
    docker run -d -p 5000:5000 --name registry registry:2

    # 2. get image ID
    sudo docker images jamtur01/static_web

    # 3. Tagging our image for our new registry
    sudo docker tag 22d47c8cb6e5 docker.example.com:5000/jamtur01/ static_web

    # 4. sudo docker push docker.example.com:5000/jamtur01/static_web

    # 5. launch container from local registry
    sudo docker run -t -i docker.example.com:5000/jamtur01/ static_web /bin/bash

4.9 Alternative Indexes

  • Quay
    • provides a private hosted registry that allows you to upload both public and private containers.

Chapter5 Testing with Docker

5.1 Using Docker to test a static website

  • Workflow
    • create Dockerfile to
      • install Nginx
      • add Nginx configuration files
      • Expose port
    • build image
    • build container from the image
    • sudo docker run -d -p 80 --name website \ -v $PWD/website:/var/www/html/website:ro \ jamtur01/nginx nginx
  • -v
    • create a volume in our container from a directory on the host
    • provide persistent or shared data for Docker. This means that changes to a volume are made directly and bypass the image
    • Use case
      • We want to work on and test it simultaneously.
      • It changes frequently, and we don’t want to rebuild the image during our development process.
      • We want to share the code between multiple containers.
  • ro, rw
    • read-write status

5.2 Using Docker to build and test a web application

  • Naive webapp
    1. create image
      1. install sinatra redis
      2. expose port
      3. run /opt/webapp/bin/webapp
    2. build image
    3. download webapp
    4. launch container with -v $PWD/webapp:/opt/webapp/
  • Webapp with Redis

    1. Prepare Redis server
      1. create image for redis server
        1. install redis-server
        2. expose port
        3. ENTRYPOINT to run redis-server
      2. Test if it works
        1. launch redis server container
        2. install redis-cli locally to test with localhost:exposedPort
    2. Prepare Docker Networking
      1. create a bridge network called app
      2. launch a Redis container called db inside the network
      3. Test if it works
        1. launch another container inside of the network
        2. install dnsutils, iputils-ping
        3. nslookup db, ping db.app
          • any host in the app network can be resolved by hostname.app
    3. Prepare Sinatra application
      1. download new webapp_redis
        1. create connection to Redis database on a host called db on port 6379
        2. with GET, POST API
      2. launch Sinatra application inside app network with -v $PWD/webapp_redis
    4. Test
      1. POST to Sinatra application, which store parameters in Redis
      2. GET to Sinatra application, which fetch parameters in Redis
  • Docker Networking

    • Docker Networking can connect containers to each other across different hosts.
    • Containers connected via Docker Networking can be stopped, started or restarted without needing to update connections.
    • With Docker Networking you don’t need to create a container before you can connect to it. You also don’t need to worry about the order in which you run containers and you get internal container name resolution and discovery inside the network.
  • Commands

Command Description
docker network ls
docker network create
docker network inspect
docker network rm
docker network connect $NETWORK $CONTAINER add already running container to existing networks
docker network disconnect $NETWORK $CONTAINER

5.3 Using Docker for continuous integration

  1. Create&Build Jenkins&Docker image
    1. Use jenkins image
    2. install docker
    3. install plugins
  2. Create Jenkin’s configuration folder
    1. locally create a jenkins folder(jenkins_home)
  3. Run container(up Jenkins server)
    • mount jenkins_home: perpetuate Jenkin’s configuration
    • mount docker.sock: run Docker containers from inside our Jenkins container
  4. Create Jenkins job
    1. set workspace as jenkins_home/xxx
    2. set Source Code as a git repo
    3. Add Build Step
      1. build image which is in workspace
      2. run container
        1. mount workspace into Build Docker
        2. Build&RunTests
        3. attach container to see output
        4. docker wait
        5. rm container
    4. Add post-build action
      • to publish test report
    5. Enabling SCM polling
      • triggers automatic build when new commits made to the repo

5.4 Multi-configuration Jenkins

What if we wanted to test our application on Ubuntu, Debian and CentOS?

  1. new job as Multi-configuration project
  2. Add Axis as {OS: {centos, debian, ubuntu}}
  3. Build Environment as Delete workspace before build starts
  4. In code repo, create centos, debian, ubuntu folders, create Dockfile in each of them
  5. Add Build Step
    1. cd $OS before doing anything

5.5 Other alternatives

i.e. other CI tools other than Jenkins

  • Drone
  • Shippable

Chapter 6 Building services with Docker

6.1 Building our first application

Volume is a specially designated directory within one or more containers that bypasses the Union File System to provide several useful features for persistent or shared data:

  • Volumes can be shared and reused between containers.
  • A container doesn’t have to be running to share its volumes.
  • Changes to a volume are made directly.
  • Changes to a volume will not be included when you update an image.
  • Volumes persist even when no containers use them.
    This allows you to add data (e.g., source code, a database, or other content) into an image without committing it to the image and allows you to share that data between containers.
  • Volumes live in Docker host var/lib/docker/volumes
  1. Build Jekyll-Apache application
    1. Build Jekyll image
      • VOLUMN /data: hold source code(why??)
      • VOLUMN /var/www/html: hold compiled Jekyll site
      • ENTRYPOINT to compile Jekyll to /var/www/html
    2. Build Apache image
      • VOLUMN /var/www/html: compiled Jekyll site
      • run apache by default
    3. Pull Git code locally
    4. Creating Jekyll container with -v codeInStep3:/data/
    5. Creating Apache container with --volumns-from containerInStep4
  2. Update Jekyll website
    1. Locally, update title then sudo docker start james_blog
      • local source code updated
      • source code mounted into Jekyll
      • start Jekyll to recompile into /var/www/html
      • Jekyll exit automatically
      • Jekyll volume into Apache automatically
      • then pages are updated
  3. Back up Jekyll volume
    • sudo docker run --rm --volumes-from james_blog \ -v $(pwd):/backup ubuntu tar cvf /backup/james_blog_backup.tar /var/www/html
      • --rm: automatically deletes the container after the process running in it is ended
      • It creates a new container to volumes-from blog
      • tar the blog
      • mounted the tared blog to local
  4. Potential extention
    1. Web cluster: run multiple Apache container, all which use the same volume from the james_blog container
    2. Generic and portable solution: make a new image to clone and mount code into Jekyll. So that we don’t need to install git and any source code locally
    3. Based on 2, we can build a web front end for our service that build and deployed sites automatically from a specific source

6.2 Building a Java application server

Fetching and running a Java application from a WAR file in a Tomcat server(Web application ARchive, we can run it directory after putting in tomcat webapp direcory)

  1. Build a WAR file fetcher
    1. VOLUME /var/lib/tomcat7/webapps/
    2. wget into the volumed dir without url
    3. Creating fetcher container with url
  2. Build tomcat server
    1. VOLUME /var/lib/tomcat7/webapps/
    2. ENTRYPOINT to run tomcat
    3. Creating tomcat container by --volumes-from fetcherContainer
  3. An extention by author
    1. He made an app called Tprov, which is a web application using for controlling step1
    2. so we can input web name, WAR url and click submit
    3. then we can see running state

6.3 A multi-container application stack

  • A big combination

    • A Node container: Node application
    • A Redis primary container: hold and cluster our state
    • 2 Redis replica container to cluster our state
    • A logging container to capture our application logs
  • Node container

    1. download nodeapp to hold application code
      • right stream to /var/log/nodeapp/nodeapp.log
      • store session in redis
      • a GET method
    2. Dockerfile
      • install nodejs npm
      • mkdir /var/log/nodeapp and VOLUME it
      • ADD nodeapp /opt/nodeapp
      • ENTRYPOINT nodejs server.js
    3. run Node container
      • -p 3000:3000 --net express
  • Redis container
    • Redis base image
      1. VOLUME var/lib/redis
      2. VOLUME var/log/redis
    • Primary Redis image
      1. only ENTRYPOINT that runs the default Redis server, which logs into var/log/redis/redis-server.log
    • Replica Redis image
      1. only ENTRYPOINT that runs a Redis replica server, which logs into var/log/redis/redis-replica.log
      2. --slaveof redis_primary 6379: this is a replica of the redis_primary host and should attempt replication on port 6379
    • Creating Redis back-end cluster
      1. create express network
      2. run redis_primary in --net express
      3. run redis_replica1 --net express
      4. run redis_replica2 --net express
      5. We can read primary Redis logs by
        • sudo docker run -ti --rm --volumes-from redis_primary ubuntu cat /var/log/redis/redis-server.log
  • Capture application logs using Logstash
    1. Dockerfile
      1. install logstash
      2. add logstash.conf in container
        • monitor logs file
        • output stdout
      3. run logstash
    2. create log app container
      1. volumes-from redis_primary and nodeapp

6.4 Managing Docker containers without SSH

sudo docker exec -ti nodeapp /bin/bash

Chapter7 Docker Orchestration and Service Discovery

7.1 Docker Compose

  • Define a set of containers to boot up and their runtime properties in a YAML file
  • this can make constructing applications from multiple Docker containers.

  • Example

    • docker-compose.yml

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      services:
      web:
      image: jamtur01/composeapp
      command: python app.py
      ports:
      - "5000:5000"
      volumes:
      - .:/composeapp
      redis:
      image: redis
    • requirements.txt

      • for pip install in Dockerfile
    • app.py
      • application file
    • Dockerfile for docker compose
      • copy everything into /composeapp
      • pip install requirements.txt
  • Commands
Command
docker-compose up
docker-compose ps
docker-compose logs
docker-compose kill
docker-compose stop
docker-compose start
docker-compose rm

7.2 Distributed application

using Consul: seems could be replaced by Docker Swarm(no need for Service Discory

7.3 Docker Swarm

  • Basic Concept
  • A swarm is made up of manager and worker nodes.
  • Manager do the dispatching and organizing of work on the swarm.
  • We can have many managers, many workers, but only one leader
  • Assume we are going to have Manager, Worker1, Worker2
  • Can be used as Load balancing

Swarm
Services

  • Commands
command description
docker node ls
docker service create --mode global: global services run on every worker in the swarm
docker service scale how many tasks to work
docker service rm
docker service ls
  • Setting up a Swarm
    • In Manager
      1. get public ip
      2. `sudo docker swarm init –advertise-addr $PUBLIC_IP
    • In worker nodes
      1. sudo docker join ...
    • Running a service on Swarm
      1. sudo docker service create --replicas 2 --name ... ubuntu /bin/sh -c "..."

7.4 Orchestration alternatives and components

Tool Name Description
Fleet cluster management tool
etcd key value store for shared configuration and service discovery
Kubernetes cluster management tool open sourced by Google
Apache Mesos cluster management tool
Helios deploying and managing containers across an entire fleet
Genturion takes containers from a Docker registry and runs them on a fleet of hosts with the correct environment variables, host volume mappings, and port mappings.
It is designed to help you do continuous deployment with Docker.

Chapter8 Using the Docker API

8.1 Docker APIs

  • Registry API
    • provides integration with the Docker registry
  • Docker Hub API
    • provides integration with the Docker Hub
  • Docker Remote API
    • provides integration with the Docker daemon

8.2 First steps with Remote API

  • the Remote API is provided by the Docker daemon
  • the Docker daemons binds to a socket, unix:///var/run/docker.sock
  • we can edit the daemon’s startup configuration files to change the bind
  • then sudo systemctl --system daemon-reload
  • test with sudo docker -H docker.example.com:port info
    • we can also export DOCKER_HOST="xxx" to throw the -H away

8.3 Testing the Docker Remote API

API description
curl http://docker.example.com:port/info docker info
curl http://docker.example.com:port/images/json docker images
curl http://docker.example.com:port/images/${id}/json `docker images ${id}
curl http://docker.example.com:port/images/search?term=...
curl http://docker.example.com:port/containers/json docker ps
curl http://docker.example.com:port/containers/json?all=1 docker ps -a
… some more POST to launch/create/run

8.4 Improving the TProv application

by ruby-docker API, for example

8.5 Authenticating the Docker Remote API

  • Create a certificate authority
  • Create a server certificate signing request and key
  • Configure the docker daemon

    1
    ExecStart=/usr/bin/docker -d -H tcp://0.0.0.0:2376 --tlsverify -- tlscacert=/etc/docker/ca.pem --tlscert=/etc/docker/server-cert. pem --tlskey=/etc/docker/server-key.pem
  • Create a client certificate and key

  • Configure the docker client using the certificates and keys

    1
    2
    3
    4
    5
    mkdir -p ~/.docker/
    cp ca.pem ~/.docker/ca.pem
    cp client-key.pem ~/.docker/key.pem
    cp client-cert.pem ~/.docker/cert.pem
    chmod 0600 ~/.docker/key.pem ~/.docker/cert.pem
  • Testing

    • sudo docker -H=docker.example.com:2376 --tlsverify info

Understanding ES6 Learning Note

Posted on 2019-10-09

Chapter1 Block Bindings

1.1 Var Declarations and Hoisting

Hoisting for var

  • If in function: as if they are at the top of the function
  • If outside of function: at the top of global scope
  • Not at the top of block
1
2
3
4
5
6
7
8
function alertValue(condition) {
if (condition) {
var value = "blue";
} else {
alert(value); // undefined instead of error
}
alert(value) // undefined instead of error
}

1.2 Block-Level Declarations

  • Block scope is created by:
    • Inside a function
    • Inside of a block (indicated by { and }
  • let (like other language)
    • In same scope
      • no redeclaration
      • can revalue
    • In different scope
      • cover
  • const

    • similar as let
    • except: cannot re-reference, while update object is fine

      1
      2
      3
      const person = { name: "Nicholas"};
      person.name = "Greg"; // works
      person = { name: "Nicholas" }; // error
  • The Temporal Dead Zone

    • var: hoist
    • let/const (in same scope)

      1. Places the declaration in the TDZ
      2. Any attempt to access a variable in the TDZ results in a runtime error
      3. That variable is only removed from the TDZ, and therefore safe to use, once execution flows to the variable declaration
      4. This even affect typeof

        1
        2
        3
        4
        5
        6
        console.log(typeof value);      // "undefined"

        if (condition) {
        console.log(typeof value); // reference error
        let value = "blue";
        }

1.3 Block Binding in Loops

  • declaration in loop

    1
    2
    3
    4
    5
    for (let i = 0; i < 10; i++) {}
    console.log(i); // error

    for (var j = 0; j < 10; j++) {}
    console.log(j) // 10
  • const in for-in and for-of

    1
    2
    3
    for (const i = 0; i < 10; i++) {}       // error

    for (const i in obj) {} // fine
  • function in loop

    1
    2
    3
    4
    5
    6
    7
    var funcs = [];
    for (var i = 0; i < 10; i++) {
    funcs.push(function() { console.log(i); });
    }
    funcs.forEach(function(func) {
    func(); // outputs the number "10" ten times
    });
    1
    2
    3
    4
    5
    6
    7
    var funcs = [];
    for (let i = 0; i < 10; i++) {
    funcs.push(function() { console.log(i); });
    }
    funcs.forEach(function(func) {
    func(); // expect output
    });

1.4 Global Block Bindings

  • var overwrites window attribute
  • let/const declare a new one in scope

Question: in global, what’s the difference between

  • var a = 123 and
  • b = 123

1.5 Emerging Best Practices for Block Bindings

  • default using const if we can
  • then use let if it might change

Chapter2 Strings and Regular Expressions

2.1 Better Unicode Support

Skip

2.2 Other String Changes

  • Identifying Substrings
    • includes()
    • startsWith()
    • endsWith()
    • repeat()

2.3 Other Regular Expression Changes

  • y Flag: sticky property
    • it tells the search to start matching characters in a string at the position specified by the regular expression’s lastIndex property.
    • lastIndex: pattern.lastIndex
    • sticky: pattern.sticky
  • Duplicating RE: let re = new RegExp(re1, "g");
  • flags property

    1
    2
    3
    let re = /ab/g;
    console.log(re.source);
    console.log(re.flags);

2.4 Template Literals

  • Multiline strings

    1
    2
    3
    4
    let html = `
    <div>
    <h1>Title</h1>
    </div>`.trim()
  • Basic string formatting

    • Substitution

      1
      2
      3
      4
      5
      let count = 10,
      price = 0.25,
      message = `${count} items cost $${(count * price).toFixed(2)}.`;

      console.log(message);
    • Tagged Templates: advanced substitution

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      function passthru(literals, ...substitutions) {
      let result = "";

      // run the loop only for the substitution count
      for (let i = 0; i < substitutions.length; i++) {
      result += literals[i];
      result += substitutions[i];
      }

      // add the last literal
      result += literals[literals.length - 1];

      return result;
      }

      let count = 10,
      price = 0.25,
      message = passthru`${count} items cost $${(count * price).toFixed(2)}.`;

      console.log(message); // "10 items cost $2.50."
  • HTML escaping

    • String.raw

      1
      2
      3
      4
      5
      6
      let message1 = `Multiline\nstring`,
      message2 = String.raw`Multiline\nstring`;

      console.log(message1); // "Multiline
      // string"
      console.log(message2); // "Multiline\nstring"

Chapter3 Functions

3.1 Functions with Default Parameter Values

  • example: function makeRequest(url, timeout = 2000, callback){}
  • The arguments object will not reflect changes to the named parameters.
  • Default Parameter Expressions
    • function add(first, second = getValue()) { return first + second;}
    • function add(first, second = first)
    • Default Parameter Value Temporal Dead Zone
      1. When executing add(), first, second are added into TDZ
      2. Initialize first then second one by one
      3. if add(first=second, second) will raise exception

3.2 Working with Unnamed Parameters

  • function pick(object, ...keys){}

3.3 Increased Capabilities of the Function Constructor

  • let add = new Function('first', 'second', 'return first+second')

3.4 The Spread Operator

  • example

    1
    2
    let values = [1, 2, 3];
    console.log(Math.max(...values, 0));

3.5 ECMAScript 6’s name Property

  • function’s property

    1
    2
    function doSomething(){}
    console.log(doSomething.name);

3.6 Clarifying the Dual Purpose of Functions

  • Two different function

    • call function with new
      • [[Construct]] method is excuted with this set
    • call function without new

      • [[Call]] method is executed

        1
        2
        3
        4
        5
        6
        7
        8
        9
        function Person(name) {
        this.name = name;
        }

        var person = new Person("Nicholas");
        var notAPerson = Person("Nicholas");

        console.log(person); // "[Object object]"
        console.log(notAPerson); // "undefined"
  • The new.target MetaProperty: solve above issue

    1
    2
    3
    4
    5
    6
    7
    function Person(name) {
    if (typeof new.target !== "undefined") {
    this.name = name;
    } else {
    throw new Error("use new");
    }
    }

3.7 Block-Level Functions

  • Difference between strict mode or not

    1
    2
    3
    4
    5
    6
    if (true) {
    console.log(typeof doSomething); // function
    let doSomething = function () {}
    }
    console.log(typeof doSomething); // throw error in strict mode
    console.log(typeof doSomething); // function in nonstrict mode

3.8 Arrow Functions

  • No this, super, arguments, and new.target bindings
  • Cannot be called with new
  • No prototype
  • Can’t change this
  • No arguments object
  • No duplicate named parameters
  • example

    1
    2
    3
    4
    5
    6
    let person = function(name) {
    return {
    getName: function() {return name;}
    };
    }("Nicholas");
    console.log(person.getName()); // "Nicholas"

3.9 Tail Call Optimization

  • With this optimization, instead of creating a new stack frame for a tail call, the current stack frame is cleared and reused
  • pre-conditions
    • The tail call does not require access to variables in the current stack frame (meaning the function is not a closure)
    • The function making the tail call has no further work to do after the tail call returns
    • The result of the tail call is returned as the function value
  • example

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // before
    function factorial(n) {
    if (n <= 1) {
    return 1;
    } else {
    // not optimized - must multiply after returning
    return n * factorial(n - 1);
    }
    }

    // after
    function factorial(n, p = 1) {
    if (n <= 1) {
    return 1 * p;
    } else {
    let result = n * p;
    // optimized
    return factorial(n - 1, result);
    }
    }

Chapter4 Expanded Object Functionality

4.1 Object Categories

Name Explanation
Ordinary objects Have all the default internal behaviors for objects in JavaScript.
Exotic objects Have internal behavior that differs from the default in some way.
Standard objects Are those defined by ECMAScript 6, such as Array, Date, and so on. Standard objects may be ordinary or exotic.
Built-in objects Are present in a JavaScript execution environment when a script begins to execute. All standard objects are built-in objects.

4.2 Object Literal Syntax Extensions

  • Property Initializer Shorthand

    1
    2
    3
    4
    5
    6
    function createPerson(name, age) { 
    return {name: name, age: age};
    }
    function createPerson(name, age) {
    return {name, age};
    }
  • Concise Methods

    1
    2
    3
    var person = {
    sayName() { console.log(this.name);}
    };
  • Computed Property Names

    1
    2
    3
    4
    5
    6
    // syntax error in ES5
    var person = {
    "first name": "Nicholas"
    };
    person["first name"] = "John";
    person["first" + suffix] = "Nicholas";

4.3 New Methods

Name Description
Object.is() Similar as ===, but better for (+0, -0) and (NaN, NaN)
Object.assign() one object receives properties and methods from another object

4.4 Duplicate Object Literal Properties

  • No error even in strict mode

    1
    2
    3
    4
    5
    6
    7
    8
    "use strict";

    var person = {
    name: "Nicholas",
    name: "Greg" // no error in ES6 strict mode
    };

    console.log(person.name); // "Greg"

4.5 Own Property Enumeration Order

  • This affects how properties are returned using
    • Object.getOwnPropertyNames()
    • Reflect.ownKeys (Chapter 12)
    • Object.assign()
  • Rule
    1. All numeric keys in ascending order
    2. All string keys in the order in which they were added to the object
    3. All symbol keys (Chapter 6) in the order in which they were added to the object

4.6 More Powerful Prototypes

  • Changing an Object’s Prototype

    • No standard way to change an object’s prototype after instantiation in ES5

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      let person = {
      getGreeting() {
      return "Hello";
      }
      };

      let dog = {
      getGreeting() {
      return "Woof";
      }
      };

      // prototype is person
      let friend = Object.create(person);
      console.log(friend.getGreeting()); // "Hello"
      console.log(Object.getPrototypeOf(friend) === person); // true

      // set prototype to dog
      Object.setPrototypeOf(friend, dog);
      console.log(friend.getGreeting()); // "Woof"
      console.log(Object.getPrototypeOf(friend) === dog); // true
  • Easy Prototype Access with Super References

    • Introduce super keyword

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      let friend = {
      getGreeting() {
      return Object.getPrototypeOf(this).getGreeting.call(this) + ", hi!";
      }
      };
      // the same as
      let friend = {
      getGreeting() {
      return super.getGreeting() + ", hi!";
      }
      };
  • Attempting to use super outside of concise methods results in a syntax error

    1
    2
    3
    4
    5
    6
    let friend = {
    getGreeting: function() {
    // syntax error
    return super.getGreeting() + ", hi!";
    }
    };

4.7 A Formal Method Definition

  • ECMAScript 6 formally defines a method as a function
  • This function has an internal [[HomeObject]] property containing the object to which the method belongs
  • The [[HomeObject]] for getGreeting() method is person
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    let person = {
    // method
    getGreeting() {
    return "Hello";
    }
    };

    // not a method: because not in an object
    function shareGreeting() {
    return "Hi!";
    }
  • Advanced knowledge: Any reference to super uses the [[HomeObject]] to determine what to do

    1. Call Object.getPrototypeOf() on the [[HomeObject]] to retrieve a reference to the prototype.
      • [[HomeObject]] of friend.getGreeting() is friend
    2. the prototype is searched for a function with the same name.
      • the prototype of friend is person
    3. the this binding is set and the method is called.

      • bind this to person
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      let person = {
      getGreeting() {
      return "Hello";
      }
      };

      // prototype is person
      let friend = {
      getGreeting() {
      return super.getGreeting() + ", hi!";
      }
      };
      Object.setPrototypeOf(friend, person);

      console.log(friend.getGreeting()); // "Hello, hi!"

Chapter5 Destructuring for Easier Data Access

5.1 Why is Destructuring Useful?

The ECMAScript 6 implementation actually use syntax for object and array literals.

5.2 Object Destructuring

  • Destructuring Assignment

    • All destructuring should be initialized when declaring
      1
      2
      3
      let { type, name } = node;
      ({ type, name } = node); //change the values of variables
      outputInfo({ type, name } = node);
  • Default Values

    1
    let { type, name, value = true } = node;
  • Assigning to Different Local Variable Names

    1
    2
    3
    let { type: localType, name: localName = "bar" } = node;    // default value

    console.log(localName); // "bar"
  • Nested Object Destructuring

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    let node = {
    type: "Identifier",
    name: "foo",
    loc: {
    start: {
    line: 1,
    column: 1
    },
    end: {
    line: 1,
    column: 4
    }
    }
    };

    // extract node.loc.start
    let { loc: { start: localStart }} = node;

    console.log(localStart.line); // 1
    console.log(localStart.column); // 1

5.3 Array Destructuring

  • Destructuring Assignment

    1
    2
    3
    4
    5
    let colors = [ "red", "green", "blue" ];

    let [ , , thirdColor ] = colors;
    [firstColor, secondColor, thirdColor] = colors; // no bracket compared with obj destruct
    [ a, b ] = [ b, a ]; // swap variable
  • Default Values

    1
    let [ firstColor, secondColor = "green" ] = colors;
  • Nested Destructuring

    1
    2
    3
    4
    let colors = [ "red", [ "green", "lightgreen" ], "blue" ];

    // later
    let [ firstColor, [ secondColor ] ] = colors;
  • Rest Items

    1
    2
    3
    let colors = [ "red", "green", "blue" ];

    let [ firstColor, ...restColors ] = colors;

5.4 Mixed Destructuring

  • Combination of Object Destructuring and Array Destructuring
  • Use case: fetch info from JSON

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    let node = {
    type: "Identifier",
    name: "foo",
    loc: {
    start: {
    line: 1,
    column: 1
    },
    end: {
    line: 1,
    column: 4
    }
    },
    range: [0, 3]
    };

    let {
    loc: { start },
    range: [ startIndex ]
    } = node;

    console.log(start.line); // 1
    console.log(start.column); // 1
    console.log(startIndex); // 0

5.5 Destructured Parameters

  • It supports everything in this chapter, including:

    • default values
    • mix object and array patterns
    • use variable names that differ from the properties

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      function setCookie(name, value, { secure, path, domain, expires }) {
      // code to set the cookie
      }

      function setCookie(name, value, {
      secure = false,
      path = "/",
      domain = "example.com",
      expires = new Date(Date.now() + 360000000
      }) {
      // with default value
      }

      setCookie("type", "js", {
      secure: true,
      expires: 60000
      });

Chapter6 Symbols and Symbol Properties

The private names proposal eventually evolved into ECMAScript 6 symbols

6.1 Creating Symbols

  • Creating and Typeof

    1
    2
    3
    let firstName = Symbol("first name");
    console.log(firstName); // print firstName.toString(), which is [[Description]]
    console.log(typeof firstName); // "symbol"

6.2 Using Symbols

  • computed object literal property names

    1
    2
    3
    let person = {
    [firstName]: "Nicholas"
    };
  • Object.defineProperty()

    1
    Object.defineProperty(person, firstName, { writable: false });

6.3 Sharing Symbols

  • create a shared symbol

    1
    2
    3
    4
    let uid = Symbol.for("uid");
    let uid2 = Symbol.for("uid");

    console.log(uid === uid2); // true
  • access global shared symbol key

    1
    console.log(Symbol.keyFor(uid2));   // "uid"

6.4 Symbol Coercion

  • Don’t do it

6.5 Retrieving Symbol Properties

  • Object.keys() and Object.getOwnPropertyNames() don’t support Symbol property
  • Instead Object.getOwnProperty-Symbols()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    let uid = Symbol.for("uid");
    let object = {
    [uid]: "12345"
    };

    let symbols = Object.getOwnPropertySymbols(object);

    console.log(symbols.length); // 1
    console.log(symbols[0]); // "Symbol(uid)"
    console.log(object[symbols[0]]); // "12345"

6.6 Exposing Internal Operations with Well-Known Symbols

  • An example

    1
    2
    3
    4
    5
    6
    let collection = {
    0: "Hello",
    1: "world",
    length: 2,
    [Symbol.isConcatSpreadable]: true
    };
  • Full list

Symbol description
Symbol.hasInstance A method used by instanceof to determine an object’s inheritance.
Symbol.isConcatSpreadable A Boolean value indicating that Array.prototype.concat() should flatten the collection’s elements if the collection is passed as a parameter to Array.prototype.concat().
Symbol.iterator A method that returns an iterator. (Chapter 8)
Symbol.match Used by String.prototype.match() to compare strings.
Symbol.replace Uused by String.prototype.replace() to replace substrings.
Symbol.search Used by String.prototype.search() to locate substrings.
Symbol.species The constructor for making derived objects. (Chapter 9)
Symbol.split Used by String.prototype.split() to split up strings.
Symbol.toPrimitive A method that returns a primitive value representation of an object.
Symbol.toStringTag Used by Object.prototype.toString() to create an object description.
Symbol.unscopables An object whose properties are the names of object properties that should not be included in a with statement.

Chapter7 Sets and Maps

7.1 Sets and Maps in ECMAScript 5

  • Example
    1
    2
    3
    4
    5
    6
    let set = Object.create(null);

    set.foo = true; // set
    set.foo = bar; // map
    if (set.foo) {
    }

7.2 Problems with Workarounds

  • a[0] and a[“0”]: different type but as same key
  • a[{}] and a[{}]: different obj but as same key

7.3 Sets in ECMAScript 6

  • Init: let a = new Map();
  • Methods:
    • add()
    • size
    • has()
    • delete()
    • clear()
  • forEach(function(next, key, ownerSet), thisArg)

    • next always equal to key
    • ownerSet: set itself
    • thisArg: defined this in function
    • Use an arrow function to get the same effect without passing thisArg
    • 1
      2
      3
      process(dataSet) {
      dataSet.forEach((value) => this.output(value));
      }
      1
      2
      3
      4
      5
      process(dataSet) {
      dataSet.forEach(function(value) {
      this.output(value);
      }, this);
      }
  • Set vs Array

convert implement
Set -> Array [...set]
Array -> Set new Set(arr);
  • Weak Set

    • Issue with Set: garbage collection

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      let set = new Set(),
      key = {};

      set.add(key);

      key = null;

      console.log(set.size); // 1

      // get the original reference back
      key = [...set][0];
    • Init weak set: new WeakSet()

    • Difference:
      1. add() can only be object
      2. Not iterable: cannot use for-of (link 8.4)
      3. Do not expose iterator: e.g. no keys(), values()
      4. No forEach()
      5. No size attribute

7.4 Maps in ECMAScript 6

  • Init:
    • let a = new Map();
    • let a = new Map([["kk", "vv"], "kkk", "vvv"]]);
  • Methods:
    • set()
    • get()
    • size
    • has()
    • delete()
    • clear()
  • forEach(): similar as Set, but callback function(key, value, ownerMet)
  • Weak Set: similar as Set

    • Only key is weak reference, not value
    • Use case:

      • associated data with DOM elements
        • key is removed authomatically while it is removed from DOM
        • never mind
      • private attribute: amazing !!!

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        let Person = (function() {

        let privateData = new WeakMap();

        function Person(name) {
        privateData.set(this, { name: name });
        }

        Person.prototype.getName = function() {
        return privateData.get(this).name;
        };

        return Person;
        }());

Chapter8 Iterators and Generators

Use case:

  • for-of
  • spread operator: ...
  • Asynchronous

8.1 The Loop Problem

8.2 What are Iterators?

  • Iterators are just objects with a specific interface designed for iteration.
  • All iterator objects have a next() method that returns
    • {value: value, done: bool}

8.3 What Are Generators?

  • Definition
    • indicated by a star character (*) after the function keyword
    • use the new yield keyword
      • yield can only be used in generator or syntax error will show up
    • fetch value by next()
  • Example

    • function keyword

      1
      2
      3
      4
      5
      6
      7
      8
      function *createIterator() {
      yield 1;
      yield 2;
      yield 3;
      }
      let iterator = createIterator();

      console.log(iterator.next().value); // 1
    • Generator Function Expression

      1
      2
      3
      let createIterator = function *(items) {
      yield items[i];
      };
    • Generator Object Methods

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      var o = {
      createIterator: function *(items) {
      yield items[i];
      }
      };

      // method shorthand
      var o = {
      *createIterator(items) {
      yield items[i];
      }
      };

8.4 Iterables and for-of

  • Iterables: An iterable is an object with a Symbol.iterator property.

  • for-of

    • for-of loop first calls the Symbol.iterator method on array/set/map to retrieve an iterator.
    • for-of loop calls next() on an iterable each time the loop executes
    • stores the value from the result object in a variable

      1
      2
      3
      4
      let values = [1, 2, 3];
      let iterator = values[Symbol.iterator]();

      console.log(iterator.next());
  • Creating Iterables
    1
    2
    3
    4
    5
    6
    7
    8
    9
    let collection = {
    items: [],
    *[Symbol.iterator]() {
    for (let item of this.items) {
    yield item;
    }
    }

    };

8.5 Built-in Iterators

  • entries(): Map default
  • keys()
  • values(): Set, Array default
  • Example

    1
    2
    3
    for (let entry of map.entries()){}
    // the same as
    for (let entry of map){} // Destructing: for (let [k, v] of map) {}
  • String, NodeList are also iterable

8.6 The Spread Operator and Non-Array Iterables

  • 1
    2
    3
    let smallNumbers = [1, 2, 3],
    bigNumbers = [100, 101, 102],
    allNumbers = [0, ...smallNumbers, ...bigNumbers];

8.7 Advanced Iterator Functionality

  • Passing Arguments to Iterators

    • The first call to next() is lost.
    • arguments passed to next() become the values returned by yield

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      function *createIterator() {
      let first = yield 1;
      let second = yield first + 2; // 4 + 2
      yield second + 3; // 5 + 3
      }

      let iterator = createIterator();

      console.log(iterator.next()); // "{ value: 1, done: false }"
      console.log(iterator.next(4)); // "{ value: 6, done: false }"
  • Throwing Errors in Iterators

    • console.log(iterator.throw(new Error("Boom")));
    • can have try-catch in generator
  • Generator Return Statements

    • indicates that all processing is done, so the done property is set to true
    • the value, if provided, becomes the value field
  • Delegating Generators

    1
    2
    3
    4
    5
    function *createCombinedIterator() {
    yield *createNumberIterator();
    yield *createColorIterator();
    yield 123;
    }

8.8 Asynchronous Task Running

  • Use case:

    • run asynchronous task by order
    • callback for asynchronous task
  • Principle

    • Store a series of asyn function in generator
    • Only after yeilding the result of an asyn function, we do next one
  • Final

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    let fs = require("fs");

    function readFile(filename) {
    return function(callback) { // the callback for result.value
    fs.readFile(filename, callback);
    };
    }

    function run(taskDef) {

    // create the iterator, make available elsewhere
    let task = taskDef();

    // start the task
    let result = task.next();

    function step() {

    if (!result.done) {
    if (typeof result.value === "function") { // check if need to run callback
    result.value(function(err, data) {
    if (err) {
    result = task.throw(err);
    return;
    }

    result = task.next(data);
    step();
    });
    } else {
    result = task.next(result.value);
    step();
    }

    }
    }

    // start the process
    step();

    }

    run(function*() {
    let contents = yield readFile("config.json");
    doSomethingWith(contents);
    console.log("Done");
    });

Chapter9 Introducing JavaScript Classes

9.1 Class-Like Structures in ECMAScript 5

  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function PersonType(name) {
    this.name = name;
    }

    PersonType.prototype.sayName = function() {
    console.log(this.name);
    };

    let person = new PersonType("Nicholas");
    person.sayName(); // outputs "Nicholas"

    console.log(person instanceof PersonType); // true
    console.log(person instanceof Object); // true

9.2 Class Declarations

9.2.1 Example

  • example

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    class PersonClass {
    constructor(name) {
    this.name = name;
    }
    sayName() {
    console.log(this.name);
    }
    }

    let person = new PersonClass("Nicholas");
    person.sayName(); // outputs "Nicholas"

    console.log(person instanceof PersonClass); // true
    console.log(person instanceof Object); // true

    console.log(typeof PersonClass); // "function"
    console.log(typeof PersonClass.prototype.sayName); // "function"
  • The PersonClass declaration actually creates a function that has the behavior of the constructor method, which is why typeof PersonClass gives “function” as the result

  • The sayName() method also becomes a method on PersonClass.prototype

9.2.2 important difference with custom types

  1. Class declarations are not hoisted. Act like let declarations and so exist in the temporal dead zone until execution reaches the declaration.
  2. All code inside of class declarations runs in strict mode automatically.
  3. All methods are non-enumerable.
  4. All methods lack an internal [[Construct]] method and will throw an error if you try to call them with new.
  5. Calling the class constructor without new throws an error.
  6. Attempting to overwrite the class name within a class method throws an error.
  • Equivalent of PersonClass, this is awesome

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    let PersonType2 = (function() {
    "use strict";
    const PersonType2 = function(name) {
    // make sure the function was called with new
    if (typeof new.target === "undefined") {
    throw new Error("Constructor must be called with new.");
    }
    this.name = name;
    }
    Object.defineProperty(PersonType2.prototype, "sayName", {
    value: function() {
    // make sure the method wasn't called with new
    if (typeof new.target !== "undefined") {
    throw new Error("Method cannot be called with new.");
    }
    console.log(this.name);
    },
    enumerable: false,
    writable: true,
    configurable: true
    });
    return PersonType2;
    }());

9.3 Class Expressions

  • 1
    2
    3
    4
    let PersonClass = class {
    //...
    }
    let p = new PersonClass("Nicholas");

9.4 Classes as First-Class Citizens

  • first-class citizen means:

    • it can be used as a value
    • it can be passed into a function
    • returned from a function
    • assigned to a variable

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      function createObject(classDef) {
      return new classDef();
      }

      let obj = createObject(class {

      sayHi() {
      console.log("Hi!");
      }
      });

      obj.sayHi();
  • creating singletons

    1
    let person = new class {...}("Nicholas");

9.5 Accessor Properties

  • getter and setter
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    class CustomHTMLElement {
    constructor(element) {
    this.element = element;
    }
    get html() {
    return this.element.innerHTML;
    }
    set html(value) {
    this.element.innerHTML = value;
    }
    }

    var descriptor = Object.getOwnPropertyDescriptor(CustomHTMLElement.prototype, "ht\
    ml");
    console.log("get" in descriptor); // true
    console.log("set" in descriptor); // true
    console.log(descriptor.enumerable); // false

9.6 Computed Member Names

  • Nothing special
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    let propertyName = "html";
    class CustomHTMLElement {
    constructor(element) {
    this.element = element;
    }
    get [propertyName]() {
    return this.element.innerHTML;
    }
    set [propertyName](value) {
    this.element.innerHTML = value;
    }
    }

9.7 Generator Methods

  • Naive example

    1
    2
    3
    4
    5
    6
    7
    8
    9
    class MyClass {
    *createIterator() {
    yield 1;
    yield 2;
    yield 3;
    }
    }
    let instance = new MyClass();
    let iterator = instance.createIterator();
  • defining a default iterator for your class

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class Collection {
    constructor() {
    this.items = [];
    }
    *[Symbol.iterator]() {
    yield *this.items.values();
    }
    }
    var collection = new Collection();
    collection.items.push(1);
    collection.items.push(2);
    collection.items.push(3);

    for (let x of collection) {
    console.log(x);
    }

9.8 Static Members

  • 1
    2
    3
    4
    5
    class PersonClass {
    static create(name) {
    return new PersonClass(name);
    }
    }

9.9 Inheritance with Derived Classes

9.9.1 Inheritance with Derived Classes

  • If specifying a constructor: super() is mandatory
  • If no constructor, super() is automatically called with all arguments upon creating a new instance of the class.
  • Can only use super() in a derived class.
  • Must call super() before accessing this in the constructor
  • The only way to avoid calling super() is to return an object from the class constructor.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Square extends Rectangle {
    // no constructor
    }
    // Is equivalent to
    class Square extends Rectangle {
    constructor(...args) {
    super(...args);
    }
    }

9.9.2 Shadowing Class Method

  • Just like other languages

    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Square extends Rectangle {
    constructor(length) {
    super(length, length);
    }
    // override and shadow Rectangle.prototype.getArea()
    getArea() {
    return this.length * this.length;
    }
    }

9.9.3 Inherited Static Members

  • Just like other languages

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    class Rectangle {
    constructor(length, width) {
    this.length = length;
    this.width = width;
    }
    getArea() {
    return this.length * this.width;
    }
    static create(length, width) {
    return new Rectangle(length, width);
    }
    }

    class Square extends Rectangle {
    constructor(length) {
    // same as Rectangle.call(this, length, length)
    super(length, length);
    }
    }

    var rect = Square.create(3, 4);

    console.log(rect instanceof Rectangle); // true
    console.log(rect.getArea()); // 12
    console.log(rect instanceof Square); // false

9.9.4 Derived Classes from Expressions

  • Special
    • You can use extends with any expression as long as the expression resolves to a function with [[Construct]] and a prototype
    • Use case: dynamic extends
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      function Rectangle(length, width) {
      this.length = length;
      this.width = width;
      }

      Rectangle.prototype.getArea = function() {
      return this.length * this.width;
      };

      function getBase() {
      return Rectangle;
      }

      class Square extends getBase() {
      constructor(length) {
      super(length, length);
      }
      }

      var x = new Square(3);
      console.log(x.getArea()); // 9
      console.log(x instanceof Rectangle); // true

9.9.5 Inheriting from Built-ins

  • Just like other languages

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class MyArray extends Array {
    // empty
    }

    var colors = new MyArray();
    colors[0] = "red";
    console.log(colors.length); // 1

    colors.length = 0;
    console.log(colors[0]); // undefined

9.9.6 The Symbol.species Property

  • Why?

    • They think subitems should not be instanceof MyArray, while I feel it’s good

      1
      2
      3
      4
      5
      6
      7
      8
      9
      class MyArray extends Array {
      // empty
      }

      let items = new MyArray(1, 2, 3, 4),
      subitems = items.slice(1, 3);

      console.log(items instanceof MyArray); // true
      console.log(subitems instanceof MyArray); // true
  • The Symbol.species well-known symbol is used to define a static accessor property that returns a function. The following builtin types have Symbol.species defined:

    • Array
    • ArrayBuffer (discussed in Chapter 10)
    • Map
    • Promise
    • RegExp
    • Set
    • Typed Arrays (discussed in Chapter 10)

9.10 Using new.target in Class Constructors

  • determine how the class is being invoked
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class Shape {
    constructor() {
    if (new.target === Shape) {
    throw new Error("This class cannot be instantiated directly.")
    }
    }
    }

    class Rectangle extends Shape {
    constructor(length, width) {
    super();
    this.length = length;
    this.width = width;
    }
    }

    var x = new Shape(); // throws error
    var y = new Rectangle(3, 4); // no error
    console.log(y instanceof Shape); // true

Chapter10 Improved Array Capabilities

  • Creating Arrays

    • Array.of()

      1
      2
      3
      Array.of(1, 2);    //[1, 2]
      Array.of(1); //[1]
      Array.of("1"); //["1"]
    • Array.from(iterable, map, this)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      let helper = {
      diff: 1,

      add(value) {
      return value + this.diff;
      }
      };

      function translate() {
      return Array.from(arguments, helper.add, helper);
      }

      let numbers = translate(1, 2, 3);

      console.log(numbers); // 2,3,4
  • New Methods on All Arrays

    • find
      • find(callback, this)
      • findIndex(callback, this)
    • fill(value, startIndex, endIndex)
    • copyWithin(startFillIndex, startCopyIndex, howMany)
  • Typed Arrays
    • Improve calculation speed
    • Skip

Chapter11 Promises and Asynchronous Programming

11.1 Asynchronous Programming Background

  • Background
    • JavaScript engines are built on the concept of a single-threaded event loop
    • Whenever a piece of code is ready to be executed, it is added to the job queue
    • job execution runs from the first job in the queue to the last
  • Old Patterns
    • The Event Model
      • chaining multiple separate asynchronous calls together is more complicated
      • button were clicked before onclick is assigned
    • The Callback Pattern
      • nested callback is dizaster
      • asynchronous operations to run in parallel

11.2 Promise Basics

  • [[PromiseState]]: not exposed
    • Fulfilled: Settled. Completed successfully.
    • Rejected: Settled. Didn’t complete successfully
    • Pending: Unsettled
  • Promise vs thenable

    • all promises are thenable
    • not all thenables are promise
    • all thenable has a then(fulFill, reject)
    • all promise has a then(fulFill, reject) and catch(reject) method

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      let promise = readFile("example.txt");

      promise.then(function(contents) {
      // fulfillment
      console.log(contents);
      }, function(err) {
      // rejection
      console.error(err.message);
      });

      // same
      promise.then(null, reject);
      promise.catch(reject);
    • Each call to then() or catch() creates a new job to be executed when the promise is resolved

    • Without a rejection handler to a promise, all failures will happen silently
  • Creating Unsettled Promises

    • new Promise(excutor)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      let fs = require("fs");

      function readFile(filename) {
      return new Promise(function(resolve, reject) {
      // trigger the asynchronous operation
      fs.readFile(filename, { encoding: "utf8" }, function(err, contents) {
      // check for errors
      if (err) {
      reject(err);
      return;
      }
      // the read succeeded
      resolve(contents);
      });
      });
      }
    • fulfillment and rejection handlers are always added to the end of the job queue after the executor has completed. Behave like setTimeout

      • example

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        let promise = new Promise(function(resolve, reject) {
        console.log("Promise");
        resolve();
        });

        promise.then(function() {
        console.log("Resolved.");
        });

        console.log("Hi!");

        // Promise
        // Hi!
        // Resolved

11.3 Global Promise Rejection Handling

  • Issue: silent failure that occurs when a promise is rejected without a rejection handler
  • Solution: Event + setInterval

    • event
      • unhandlerejection
      • rejectionhandled
    • setInterval
    • example

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      let possiblyUnhandledRejections = new Map();
      window.onunhandledrejection = function(event) {
      possiblyUnhandledRejections.set(event.promise, event.reason);
      };
      window.onrejectionhandled = function(event) {
      possiblyUnhandledRejections.delete(event.promise);
      };

      setInterval(function() {
      possiblyUnhandledRejections.forEach(function(reason, promise) {
      handleRejection(promise, reason);
      });
      possiblyUnhandledRejections.clear();

      }, 60000);

11.4 Chaining Promises

  • Each call to then() or catch() actually creates and returns another promise
  • This second promise is resolved only once the first has been fulfilled or rejected
  • example

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    let p1 = new Promise(function(resolve, reject) {resolve(42);});

    p1.then(function(value) {
    console.log(value);
    }).then(function() {
    console.log("then");
    throw new Error("Boom");
    }).catch(function(error) {
    console.log(error.message);
    });
  • Returning Values in Promise Chains

    • data

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      let p1 = new Promise(function(resolve, reject) {
      reject(42);
      });

      p1.catch(function(value) {
      console.log(value); // "42"
      return value + 1;
      }).then(function(value) {
      console.log(value); // "43"
      });
    • Promise

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      let p1 = new Promise(function(resolve, reject) {
      reject(42);
      });

      p1.catch(function(value) {
      console.log(value); // "42"
      let p2 = new Promise(function(resolve, reject) {
      reject(43);
      });
      return p2
      }).then(function(value) {
      console.log(value); // "43"
      });

11.5 Responding to Multiple Promises

  • Promise.all()
    • The returned promise is fulfilled when every promise in the iterable is fulfilled
    • If anyone is rejected, it is immediately rejected without waiting for others
  • Promise.race()
    • returns as soon as any promise in the array is fulfilled
    • if the first promise to settle is rejected, then the returned promise is rejected

11.6 Inheriting from Promises

  • Since static methods are inherited, resolve(), reject(), race(), all() method are also present on derived promises
  • Because of Symbol.species, resolve(), reject() will tag class as the derived class

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    let p1 = new Promise(function(resolve, reject) {
    resolve(42);
    });

    let p2 = MyPromise.resolve(p1);
    p2.success(function(value) {
    console.log(value); // 42
    });

    console.log(p2 instanceof MyPromise); // true

Chapter12 Proxies and the Reflection API

  • Proxies exposes the inner workings of objects through
  • Proxies can intercept and alter low-level operations of the JavaScript engine.

12.1 The Array Problem

  • User cannot do arr.length = 2

12.2 What are Proxies and Reflection?

Proxy Trap Overrides the Behavior Of Default Behavior
get Reading a property value Reflect.get()
set Writing to a property Reflect.set()
has The in operator Reflect.has()
deleteProperty The delete operator Reflect.deleteProperty()
getPrototypeOf Object.getPrototypeOf() Reflect.getPrototypeOf()
setPrototypeOf Object.setPrototypeOf() Reflect.setPrototypeOf()
isExtensible Object.isExtensible() Reflect.isExtensible()
preventExtensions Object.preventExtensions() Reflect.preventExtensions()
getOwnPropertyDescriptor Object.getOwnPropertyDescriptor() Reflect.getOwnPropertyDescriptor()
defineProperty Object.defineProperty() Reflect.defineProperty
ownKeys Object.keys, Object.getOwnPropertyNames(), Object.getOwnPropertySymbols() Reflect.ownKeys()
apply Calling a function Reflect.apply()
construct Calling a function with new Reflect.construct()
  • example set: only allow numbers for new property

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    let target = {
    name: "target"
    };

    let proxy = new Proxy(target, {
    set(trapTarget, key, value, receiver) {

    // ignore existing properties so as not to affect them
    if (!trapTarget.hasOwnProperty(key)) {
    if (isNaN(value)) {
    throw new TypeError("Property must be a number.");
    }
    }

    // add the property
    return Reflect.set(trapTarget, key, value, receiver);
    }
    });

    // adding a new property
    proxy.count = 1;
    console.log(proxy.count); // 1
    console.log(target.count); // 1

    // you can assign to name because it exists on target already
    proxy.name = "proxy";
    console.log(proxy.name); // "proxy"
    console.log(target.name); // "proxy"

    // throws an error
    proxy.anotherName = "proxy";
  • Revocable Proxies

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    let target = {
    name: "target"
    };

    let { proxy, revoke } = Proxy.revocable(target, {});

    console.log(proxy.name); // "target"

    revoke();

    // throws error
    console.log(proxy.name);

Chapter13 Encapsulating Code With Modules

13.1 What are Modules?

  • Variables created in the top level of a module exist only within the top-level scope of the module.
  • The value of this in the top level of a module is undefined.
  • Modules must export anything that should be available to code outside of the module.
  • Modules may import bindings from other modules.

13.2 Basic Exporting

  • any variables, functions, or classes that are not explicitly exported remain private to the module
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // export data
    export var color = "red";
    export let name = "Nicholas";
    export const magicNumber = 7;

    // export function
    export function sum(num1, num2) {
    return num1 + num1;
    }

    // export class
    export class Rectangle {
    constructor(length, width) {
    this.length = length;
    this.width = width;
    }
    }

13.3 Basic Importing

  • An important limitation of both export and import is that they must be used outside other statements and functions
  • 1
    2
    3
    import { identifier1, identifier2 } from "./example.js";
    import { sum } from "./example.js";
    import * as example from "./example.js";

13.4 Renaming Exports and Imports

  • 1
    2
    3
    4
    5
    function sum(num1, num2) {
    return num1 + num2;
    }

    export { sum as add };
  • 1
    import { add as sum } from "./example.js";

13.5 Default Values in Modules

  • 1
    2
    3
    export default function(num1, num2) {
    return num1 + num2;
    }
  • 1
    2
    import sum from "./example.js";
    import sum, {color} from "./example.js";

13.6 Re-exporting a Binding

  • 1
    2
    3
    4
    import { sum } from "./example.js";
    export { sum };
    // same as
    export { sum } from "./example.js";

13.7 Importing Without Bindings

  • Some modules may only make modifications to objects in the global scope
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // module code without exports or imports
    Array.prototype.pushAll = function(items) {

    // items must be an array
    if (!Array.isArray(items)) {
    throw new TypeError("Argument must be an array.");
    }

    // use built-in push() and spread operator
    return this.push(...items);
    };

13.8 Loading Modules

  • 1
    <script type="module" src="module.js"></script>
  • To support that functionality, always acts as if the defer attribute is applied

  • Modules are also executed in the order in which they appear in the HTML file
  • async
    • All resources the module needs will be downloaded before the module executes
    • can’t guarantee when the module will execute
  • Loading Modules as Workers
    • let worker = new Worker("module.js", { type: "module" });
  • Browser Module Specifier Resolution
    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      // this script locates https://www.example.com/modules/module.js

      // imports from https://www.example.com/modules/example1.js
      import { first } from "./example1.js";

      // imports from https://www.example.com/example2.js
      import { second } from "../example2.js";

      // imports from https://www.example.com/example3.js
      import { third } from "/example3.js";

      // imports from https://www2.example.com/example4.js
      import { fourth } from "https://www2.example.com/example4.js";

Professional Javascript For Web Developer Learning Note

Posted on 2019-06-15 | Edited on 2019-10-09

Chapter2 JavaScript in HTML

2.1 The <script> Element

  • Attribute for script
Attribute Description
async Indicates that the script should begin downloading immediately but should not prevent other actions on the page
charset
defer deferred until after the document’s content has been completely parsed and displayed
src
type default text/javascript
  • Without defer and async, the <script> elements are interpreted in the order in which they appear in the page

2.2 Inline Code Versus External Files

2.3 Document Mode

2.4 The <noscript> Element

  • If browser does not support Javascript, it will show up

    1
    2
    3
    4
    5
    <body>
    <noscript>
    <p>This page requires a JavaScript-enabled browser.</p>
    </noscript>
    </body>

Chapter3 Language Basics

3.1 Syntax

Strict mode

  • Some of the erratic behavior of ECMAScript 3 is addressed and errors are thrown for unsafe activities
  • Enable strict mode for an entire script: include "use strict"; in js top
  • Enable strict mode for a function:

    1
    2
    3
    4
    function doSomething() {
    "use strict";
    // code
    }

3.2 Keywords And Reserved Words

3.3 Variables

  • ECMAScript variables are loosely typed
  • Scope

    1
    2
    3
    4
    function test() {
    var a = 1; // local variable
    b = 2; // global variable
    }

3.4 Data Types

  • There are five primitive types in ECMAScript:
    • Undefined
    • Null
    • Boolean
    • Number
    • String

3.4.1 The typeof Operator

  • Usage

    1
    2
    3
    var msg = "aaa";
    alert(typeof msg);
    alert(typeof(msg));
  • Return string
Return Description
undefined if the value is undefined
boolean
string
number
object if the value is an object or null
function

3.4.2 The Undefined Type

1
2
3
4
5
6
7
8
var a;
var b = undefined;

alert(a == undefined); // declared: true
alert(b == undefined); // true
alert(b); // "undefined"
alert(c == undefined); // error
alert(typeof c); // "undefined", this is weird

3.4.3 The Null Type

  • A null value is an empty object pointer
    • so typeof null === "object" //true
  • The value undefined is a derivative of null
    • so null == undefined //true

3.4.4 The Boolean Type

Type Values converted to true Values converted to false
Boolean true false
String Any nonempty string “”
Number Any nonzero number 0
Object Any object null
Undefined NA undefined

3.4.5 The Number Type

  • base 8: var octalNum = 070;
  • base 16: var hexNum = 0xA;
  • e-notation: var floatNum = 3.125e7
  • Infinity
    • max number: Number.MAX_VALUE
    • min number: Number.MIN_VALUE
    • positive infinity: Infinity or Number.POSITIVE_INFINITY
    • negative infinity: -Infinity or Number.NEGATIVE_INFINITY
    • isInfinite(xxx)
  • NaN(Not a Number)
    • any number divided by not number: 10/"abc"
    • any NaN operation: NaN/10
    • NaN is not equal to any value, including NaN: NaN == NaN //false
    • isNaN(): determine if the value is “not a number.”
  • Number Conversions
    • Number()
    • parseInt()
    • parseFloat()

      3.4.6 The String Type

  • Immutable
  • If the value has a toString() method, it is called (with no arguments) and the result is returned.
  • If the value is null, “null” is returned.
  • If the value is undefined, “undefined” is returned

3.4.7 The Object Type

  • var o = new Object()
  • Each Object instance has the following properties and method
Property Description
constructor function that was used to create the object
hasOwnProperty(propertyName) Indicates if the given property exists on the object instance (not on the prototype)
isPrototypeOf(object) Determines if the object is a prototype of another object
propertyIsEnumerable(propertyName) using the for-in statemen
toLocaleString()
toString()
valueOf()

3.5 Operators

  • Identically Equal and Not Identically Equal
    • 55 == "55" //true
    • 55 === "55" //false

3.6 Statement

  • Labeled Statement
    • label: statement
    • used with continue and break
  • The With Statement

    • The with statement sets the scope of the code within a particular object

      1
      2
      3
      4
      5
      6
      7
      8
      var qs = location.search.substring(1); 
      var hostName = location.hostname;
      var url = location.href;
      // the same as
      with(location){
      var qs = search.substring(1); var hostName = hostname;
      var url = href;
      }
* DO NOT USE WITH: 

> Chapter 24.2: With statement creates its own scope and therefore increases the length of the scope chain for code executed within it 

3.7 Functions

  • Parameters are only for convenience:

    1
    2
    3
    4
    5
    function sayHi(a, b) {
    alert(typeof b);
    alert(typeof a);
    }
    sayHi(123); // it works
  • arguments in function

    • arguments.length
    • arguments[0] but arguments is not an Array instance
  • No Overloading

Chapter4 Variables, Scope, and Memory

4.1 Primitive And Reference Values

  • Similar as Python:
    • primitive type copy value: stored in stack
    • reference type copy reference (pointer): stored in heap
  • instanceof: if the variable is an instance of the given reference type

    1
    2
    3
    alert(person instanceof Object);
    alert(colors instanceof Array);
    alert(pattern instanceof RegExp);

4.2 Execution Context And Scope

  • Each execution context has an associated variable object upon which all of its defined variables and functions exist
  • There are only two primary types of execution contexts
    • global
    • function (local)

4.2.1 Scope Chain Augmentation

  • There are two way to augment the scope chain
    • try-catch
    • with

4.2.2 No Block-Level Scopes

1
2
3
4
for(var i = 0; i < 10; i++){
console.log(i);
}
alert(i); //10

4.3 Garbage Collection

  • Two ways:
    • mark-and-sweep
    • reference counting

4.3.1 mark-and-sweep:

  • Delete variable that cannot be fetched

4.3.2 reference counting

  • Delete variable that reference count == 0
  • Issue: circular reference

    1
    2
    3
    4
    var element = document.getElementById("some_element"); 
    var myObject = new Object();
    myObject.element = element;
    element.someObject = myObject;

4.3.3 Performance

4.3.4 Managing Memory

Dereference

The point of dereferencing is to make sure the value is out of context and will be reclaimed the next time garbage collection occurs. e.g.

1
2
var p = createPerson("name");
p = null;

Chapter5 Reference Types

5.1 The Object Type

  • Two ways to explicitly create an instance of Object:

    1
    2
    3
    4
    5
    var person = new Object();          // constructor
    person.age = 10;
    person.name = "aaa";

    var person = {age:10, name:"aaa"}; // object literal notation
  • Two ways to access attribute
    • person.name: preferred
    • person["name"]: used in case like person["last name"]

5.2 The Array Type

  • Two ways to explicitly create an instance of Array:

    1
    2
    3
    4
    5
    6
    var colors = new Array();   // constructor
    var colors = new Array(20); // length
    var colors = new Array(1, "aaa", obj); // can store any types

    var colors = []; // array literal notation
    var colors = [1, 3];
  • access, update

    1
    2
    3
    4
    5
    6
    var colors = [1, 3];
    colors[4] = "aaa"; // [1, 3, , , "aaa"]
    colors[3]; // undefined
    colors.length = 2; // [1, 3]
    colors.length = 6; // [1, 3, , , ,]
    colors[3]; // undefined

5.2.1 Detecting Arrays

  • Reason:
    • The one problem with instanceof assumes a single global execution context
    • If an array was passed from one frame into another frame, that array has a different constructor function.
    • So instanceof fail.
  • Solution
    • if (Array.isArray(colors))

5.2.2 Conversion Methods

  • toLocalString()
  • toString()
  • valueOf()

5.2.3-5.2.7

var nums = [0, 1, 2]

Type Function Description
Stack push(1, 2) [0, 1, 2, 1, 2]
Stack pop() [0, 1]
Queue shift() [1, 2]
Queue unshift(1, 2) [1, 2, 0, 1, 2]
Reordering reverse() [2, 1, 0]
Reordering sort(func) a function for comparation
Manipulation concat(3, [4, 5]) [0, 1, 2, 3, 4, 5]
Manipulation slice() slice(1): from index 1 to last
slice(1, 2): from index 1 to index 2 (excluded)
Matipulation splice() deletion: splice(0, 3) // delte from index 0 for 3 element
insertion: splice(2, 0, “123”) // insert “123” into index 2, delete 0 element
replacement: splice(2, 1, “123”) // insert “123” into index 2, delete 1 element
Location indexOf() search from first element
Location lastIndexOf() search from last element
Iterative every() colors.every(function(item, index, array) {return item > 2;});
Iterative some() similar as every()
Iterative filter() colors.filter(function(item, index, array) {return item > 2;});
Iterative forEach() colors.map(function(item, index, array) {...});
Iterative map() colors.map(function(item, index, array) {return item * 2;});
Reduction reduce() like foldl in Go. From first item
Reduction reduceRight() like foldr in Go. From last item

5.3 THE DATE TYPE

Hard to say

5.4 THE REGEXP TYPE

flags:

Type Description
g global
i case insensitive
m multiline
1
2
var re = /[bc]at/i;     // var expression = /pattern/ flags
var re = new RegExp("[bc]at", "i"); // var expression = new RegExp(patternString, flags);

5.4.1 RegExp Instance Properties

Type Description
global if g
ignoreCase if i
multiline if m
lastIndex start position of next search
source pattern information

5.4.2 RegExp Instance Methods

  • exec()

    1
    2
    3
    4
    5
    6
    var text = "...";
    var pattern = /xxx/;
    var matches = pattern.exec(text);
    alert(matches.index);
    alert(matches.input);
    alert(matches[0]);
  • test():
    pattern.test(text) // return boolean

5.4.3 RegExp Constructor Properties

VERBOSE NAME SHORT NAME
input $_
lastMatch $&
lastParen $+
leftContext $`
multiline $*
rightContext $’

usage:

1
2
3
4
5
if (pattern.test(text)) {
alert(RegExp.input);
alert(RegExp.$_);
alert(RegExp["$'"]);
}

5.4.4 Pattern Limitations

5.5 The Function Type

  • Each function is an instance of the Function type
  • Functions are actually Object
    • func instanceof Object // true
  • Function names are actually reference

Three ways to creat a function:

1
2
3
4
5
6
7
// function declaration
function sum (num1, num2) {...}

// function expression
var sum = function(num1, num2) {...};

var sum = new Function("num1", "num2", "return num1 + num2"); // not recommended

5.5.1 No Overloading

Because function name is reference

5.5.2 Function Declarations versus Function Expressions

  • Function declarations are read and available in an execution context before any code is executed
  • Function expressions aren’t complete until the execution reaches that line of code.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // works
    alert(sum(10, 10));
    function sum(num1, num2) {
    return num1 + num2;
    }

    // error
    alert(sum(10, 10));
    var sum = function(num1, num2) {
    return num1 + num2;
    };

5.5.3 Functions as Values

  • function can be parsed as argument and return

5.5.4 Function Internals

  • arguments
    • arguments.callee: the function, can be used for recursion
  • this

    • It is a reference to the context object that the function is operating on.

      1
      2
      3
      4
      5
      6
      7
      window.color = "red";
      var o = { color: "blue" };
      function sayColor(){ alert(this.color);}

      sayColor(); //"red"
      o.sayColor = sayColor;
      o.sayColor(); //"blue"

Original Discussion

The interpreter updates the ThisBinding whenever establishing an execution context in one of only three different cases:

  1. Initial global execution context
  2. Entering eval code
  3. Entering function code
    • In most other cases, ThisBinding is set to the global object
    • If a function is called on an object, such as in obj.myMethod() or the equivalent obj["myMethod"](), then ThisBinding is set to the object.
      • Opposite: var a = obj.myMethod; a(); this bind to window
    • These special functions take a so-called thisArg which becomes the ThisBinding when calling the function
      • Function.prototype.apply( thisArg, argArray )
      • Function.prototype.call( thisArg [ , arg1 [ , arg2, … ] ] )
      • Function.prototype.bind( thisArg [ , arg1 [ , arg2, … ] ] )
      • Array.prototype.every( callbackfn [ , thisArg ] )
      • Array.prototype.some( callbackfn [ , thisArg ] )
      • Array.prototype.forEach( callbackfn [ , thisArg ] )
      • Array.prototype.map( callbackfn [ , thisArg ] )
      • Array.prototype.filter( callbackfn [ , thisArg ] )
  4. new operation
1
2
3
4
5
6
7
8
function MyType() {
this.someData = "a string";
}
var instance = new MyType();

// similar as:
var instance = {};
MyType.call(instance);
  • caller
    • A reference to the function that called this function or null if the function was called from the global scope.

5.5.5 Function Properties and Methods

Two properties

  • length: number of arguments expected
  • prototype
    • actual location of all instance methods for reference types
    • methods such as toString(), valueOf() exist on prototype

Two methods

  • func.apply(context, arguments):

    1
    2
    3
    4
    5
    6
    7
    8
    function sum(num1, num2) {return num1 + num2;}

    function callSum(num1, num2) {
    // so this refer to global. The same as call sum(arguments) in global
    return sum.apply(this, arguments);
    }

    alert(callSum(10, 10)); // this function is invoked in global
  • func.call(context, arg1, arg2, …)
    • Similar as apply()
    • Only difference is argument should be parsed one by one
    • Usage: sum.call(this, num1, num2);
  • Their ability to augment context inside of the function

    1
    2
    3
    sayColor.call(this);
    sayColor.call(window);
    sayColor.call(obj);
  • bind(context)

    • It returns a function instance
    • bind this to function

      1
      2
      3
      4
      5
      6
      var o = {"color": "blue"};
      function sayColor() {
      alert(this.color);
      }
      var objSayColor = sayColor.bind(o);
      objSayColor(); // blue

5.6 Primitive Wrapper Types

Three special reference types:

  • The Boolean type: var b = new Boolean(false)
  • The Number type: var n = new Number(10)
  • The String type: var s = new String("abbb")

Reason:

  • "aaaaa".substring(2) is valid
  • “aaaaa” is primitive type, shoule not have method. These steps happened:
    1. Create an instance of the String type.
    2. Call the specified method on the instance.
    3. Destroy the instance.

5.6.1 The Boolean Type

DO NOT USE IT.
Unexpted behaviour when doing logic operation

5.6.2 The Number Type

Method Description
valueOf()
toLocaleString()
toString()
toFixed() 10.005.toFixed(2) // 10.01
toExponential() 10.toExponential(1) // 1.0e+1
toPrecision() fixed or exponential

5.6.3 The String Type

Type Method
Character Methods charAt()
charCodeAt()
“xxx”[0]
String-Manipulation Methods concat()
slice()
substring()
substr()
String Location Methods indexOf()
lastIndexOf()
The trim() Method trim()
String Case Methods toLowerCase()
toLocalLowerCase()
toUpperCase()
toLocalUpperCase()
String Pattern-Matching Methods 5.4 RE
match()
replace()
htmlEscape()
split()
The localeCompare() Method
The fromCharCode() Method
HTML Methods

5.7 Singleton Built-In Objects

5.7.1 The Global Object

  • All variables and functions defined globally become properties of the Global object
  • All variables and functions are Global methods. e.g. parseInt(), isNaN()
  1. URI-Encoding Methods

    • encodeURI()/decodeURI()
    • encodeURIComponent()/decodeURIComponent()
  2. The eval() Method

    • It interprets the argument into actual ECMAScript statements and then inserts it into place
    • Has the same scope chain

      1
      2
      eval("function sayHi() {alert('hi');}");
      sayHi()

Global Object Properties

  • Special Values:

    • undefined
    • NaN
    • Infinity
  • Constructors:

    • Object, Array, Function, Boolean, String, Number, Date, RegExp, Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError

The Window Object

  • Though ECMAScript doesn’t indicate a way to access the Global object
  • Web browsers implement it such that the window is the Global object’s delegate
  • The window object does much more in JavaScript than just implement the ECMAScript Global object

    1
    2
    3
    4
    5
    var color = "red";
    function sayColor(){
    alert(window.color);
    }
    window.sayColor(); //"red"

5.7.2 The Math Object

Properties

  • Math.E, Math.LN10, Math.LN2, Math.LOG2E, Math.LOG10E, Math.PI, Math.SQRT1_2, Math.SQRT2

Methods

  • min(), max()
  • ceil(), floor(), round()
  • random()
  • abs(), exp(), log(), pow(), sqrt(), acos(), asin(), atan(), atan2(), cos(), sin(), tan()

Chapter6 Object-Oriented Programming

6.1 Understanding Objects

6.1.1 Types of Properties

  • Data Property:
    • Each data property has 4 attributes
Name Description
[[Configurable]] if can be delete person.name, false: cannot change any attributes
[[Enumerable]] if the property can be for-in loop
[[Writable]] if value can be changed
[[Value]] the value
  • Accessor Properties
    • It defines getter and setter
Name Description
[[Configurable]] same
[[Enumerable]] same
[[Get]] getter
[[Set]] setter

6.1.2 Defining Multiple Properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var person = {};
Object.defineProperty(person,
name: {
get: function() {
return this._name + "d";
}
set: function(newValue) {
this._name = newValue + "dd"
}
},
age: {
writable: false,
value: 10
}
);

6.1.3 Reading Property Attributes

1
2
var descriptor = Object.getOwnPropertyDescriptor(person, "name");
alert(description.value);

6.2 Object Creation

6.2.1 The Factory Pattern

1
2
3
4
5
6
function createPerson(name, age){ 
var o = new Object();
o.name = name;
o.sayName = function() {alert(this.name); };
return o;
}
  • Disadvantage:
    • Cannot know instance type
    • Different people has different sayName function

6.2.2 The Constructor Pattern

1
2
3
4
function Person(name, age){ 
this.name = name;
this.sayName = function() {alert(this.name); };
}}
  • Advantages:

    1
    2
    3
    var person1 = new Person("N", 11);
    person1.constructor == Person // true
    person1 instanceOf Person // true
  • Disadvantages:
    • Different people has different sayName function
    • Make sayName global then this.sayName = sayName is not a solution since the method should be private
    • User is able to call Person(xx, xx) without new, then it sets global attribute

6.2.3 The Prototype Pattern

Prototype

  • By scope chain:

    • person1.name first search person1 attribute then its Prototype
    • person1.sayName() first search person1 then its Prototype
  • Advantages:

    • person1.name == "NG" covers the Prototype one
    • delte person1.name can recover it
    • all person instances share the same sayName function
  • Disadvantages:

    • different people should have different attributes
    • If the name is an Object, it is mutable and change the name of all persons
  • Syntax

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function Person(){}
    Person.prototype = {
    constructor: Person,
    name : "Nicholas",
    age : 29,
    sayName : function () {
    alert(this.name);
    }
    };
  • Some methods

    1
    2
    3
    4
    5
    6
    7
    8
    9
    Object.getPrototypeOf(person1) == Person.prototype   // true
    Object.getPrototypeOf(person1).name // "Nicholas"
    person1.hasOwnProperty("name") // false: if returned attribute got from instance
    person1.hasOwnPrototypeProperty("name") // true: if returned attribute got from prototype
    "name" in person1 // true: if has "name" no matter in instance or prototype


    Object.keys() // all instance enumerated attributes
    Object.getOwnPropertyNames() // all instance attributes even not enumerated

6.2.4 Combination Constructor/Prototype Pattern

1
2
3
4
5
6
7
8
9
10
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype = {
constructor: Person,
sayName : function () {
alert(this.name);
}
};
  • Disadvantage:
    • Confused because having two code blocks for a class

6.2.5 Dynamic Prototype Pattern

1
2
3
4
5
6
7
8
9
10
function Person(name, age){
this.name = name;
this.age = age;

if (typeof this.sayName != "function") {
Person.prototype.sayName = function(){
alert(this.name;)
};
}
}

6.2.6 Parasitic Constructor Pattern

1
2
3
4
5
6
7
8
9
10
function Person(name, age, job){ 
var o = new Object();
o.name = name;
o.age = age;
o.sayName = function(){
alert(this.name); };
return o;
}
var friend = new Person("Nicholas", 29);
friend.sayName(); //"Nicholas"

Does not make sense!!! Cannot see any advantages over 6.2.5

6.2.7 Durable Constructor Pattern

1
2
3
4
5
6
7
function Person(name, age, job){
var o = new Object();
o.sayName = function(){
alert(name);
};
return o;
}

Does not make sense!!! Cannot see any advantages over 6.2.5

6.3 Inheritance

6.3.1 Prototype Chaining (hardly use)

The basic idea is to use the concept of prototypes to inherit properties and methods between two reference types

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function SuperType(){ 
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
};
function SubType(){
this.subproperty = false;
}

//inherit from SuperType
SubType.prototype = new SuperType();

// new method
SubType.prototype.getSubValue = function (){
return this.subproperty;
};

//override existing method. should below new SuperType() !!
SubType.prototype.getSuperValue = function (){
return false;
};


var instance = new SubType();
alert(instance.getSuperValue()); //true

Inheritance

1
2
3
4
5
6
7
alert(instance instanceof Object);      // true
alert(instance instanceof SuperType); // true
alert(instance instanceof SubType); // true

alert(Object.prototype.isPrototypeOf(instance)); //true
alert(SuperType.prototype.isPrototypeOf(instance)); //true
alert(SubType.prototype.isPrototypeOf(instance)); //true
  • Issues:

    1. When prototypes contain reference values

      1
      2
      3
      4
      5
      6
      7
      function SuperType() {
      this.colors = ["r", "g", "b"]
      }
      ...

      instance1.colors.push("w");
      alert(instance2.colors); // r, g, b, w
    2. cannot pass arguments into the supertype

6.3.2 Constructor Stealing

1
2
3
4
5
6
7
8
9
10
11
12
function SuperType(name){ 
this.name = name;
}
function SubType(){
//inherit from SuperType passing in an argument
SuperType.call(this, "Nicholas"); // SuperType.call("Nicholas") will bind name to window
//instance property
this.age = 29;
}
var instance = new SubType();
alert(instance.name); //"Nicholas";
alert(instance.age); //29

Because of 5.5.4, it cannot be SuperType.call(“Nicholas”)

  • Advantages: It solves 6.3.1 issues.

  • Disadvantages:

    1. no function reuse. (instances have their own function)
    2. methods defined on the supertype’s prototype are not accessible on the subtype

6.3.3 Combination Inheritance

(combined with 6.3.1 and 6.3.2)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name, age){
//inherit properties
SuperType.call(this, name);
this.age = age;
}
//inherit methods
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function(){
alert(this.age);
};
  • Advantage:

    1. The most frequently used inheritance pattern in JavaScript.
    2. instanceof, isPrototypeOf() also work
  • Disadvantage:

    1. call two times of SuperType()

6.3.4 Prototypal Inheritance

Basic idea:

1
2
3
4
5
function object(o){ 
function F(){}
F.prototype = o;
return new F();
}

ECMA5: formalized the concept of prototypal inheritance by Object.create(parentInstance)

1
2
3
4
5
6
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = Object.create(person);
anotherPerson.name = "Greg";
  • Advantages: easy
  • Disadvantages:
    • need a parent instance created
    • share mutable type attributes. i.e. friends list

6.3.5 Parasitic(寄生式) Inheritance

Similar as 6.3.4

1
2
3
4
5
6
7
function createAnother(original){ 
var clone = object(original);
clone.sayHi = function(){
alert("hi");
};
return clone;
}

Disadvantage:

* the same as 6.3.4
* function reuse inefficiencies

6.3.6 Parasitic Combination(寄生组合式)Inheritance

看不懂!!!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function inheritPrototype(subType, superType){ 
// prototype这个实例的prototype是superType的prototype
var prototype = object(superType.prototype); //create object
prototype.constructor = subType; //create object
subType.prototype = prototype; //assign object
}

function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name, age){
SuperType.call(this, name);
this.age = age;
}
inheritPrototype(SubType, SuperType);

SubType.prototype.sayAge = function(){
alert(this.age);
};

Parasitic combination inheritance is considered the most efficient way to implement type-based inheritance.

Chapter7 Function Expressions

7.1 Recursion

  • use arguments.callee
  • a special implementation

    1
    2
    3
    4
    5
    6
    7
    8
    var factorial = (function f(num) {
    if (num <= 1) {
    return 1;
    }
    else {
    return num * f(num-1);
    }
    }

7.2 Closure

Closures are functions that have access to variables from another function’s scope. This is often accomplished by creating a function inside a function

7.2.1 Closures and Variables

Should understand the difference between

1
2
3
4
5
6
7
8
9
function createFunctions(){ 
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(){
return i; // this i is a reference
};
}
return result;
}
1
2
3
4
5
6
7
8
9
10
function createFunctions(){ 
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(num){
return function(){
return num;
};
}(i); // this i is parsed(value copy) in
}
return result; }

7.2.2 The this Object

Should understand the difference between

1
2
3
4
5
6
7
8
9
10
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()()); //"The Window" (in non-strict mode)
1
2
3
4
5
6
7
8
9
10
11
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this; // this is the obj, so we need a variable to refer
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()()); //"My Object"

7.2.3 Memory Leaks

Closure will store variables in memory and cannot be destroied.

1
2
3
4
5
6
function assignHandler(){
var element = document.getElementById("someElement");
element.onclick = function(){
alert(element.id);
};
}
  • Solution

    1
    2
    3
    4
    5
    6
    7
    8
    function assignHandler(){
    var element = document.getElementById("someElement");
    var id = element.id;
    element.onclick = function(){
    alert(id);
    };
    element = null;
    }

7.3 MIMICKING BLOCK SCOPE

JavaScript has no concept of block-level scoping

1
2
3
4
for (var i=0; i < 2; i++){
alert(i);
}
alert(i); // 2
  • Solution

    1
    2
    3
    4
    var someFunction = function(){ 
    //block code here
    };
    someFunction();
    1
    2
    3
    4
    5
    6
    7
    function(){
    //block code here
    }(); //error! Because of Javascript declaration hoisting

    (function(){
    //block code here
    })(); //fine

7.4 PRIVATE VARIABLES

Privileged method: two ways

1
2
3
4
5
6
7
8
9
10
function MyObject(){
//private variables and functions
var privateVariable = 10;
function privateFunction(){ return false;}
//privileged methods
this.publicMethod = function (){
privateVariable++;
return privateFunction();
};
}
1
2
3
4
5
6
7
8
function Pewrson(name) {
this.getName = function() {
return name;
}
this.setName = function() {
name = value;
}
}

Disadvantage: each time new Person, new functions are created

7.4.1 Static Private Variables

1
2
3
4
5
6
(function(){
var name = "";
Person = function(value){ name = value;};
Person.prototype.getName = function(){ return name;};
Person.prototype.setName = function (value){ name = value;};
})();

Disadvantage: All instance name will be shared and set

7.4.2 The Module Pattern

Create private variable and privileged method for singleton

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var singleton = function(){
//private variables and functions
var privateVariable = 10;
function privateFunction(){
return false;
}
//privileged/public methods and properties
return {
publicProperty: true,
publicMethod : function(){
privateVariable++; // closure
return privateFunction();
}
};
}();

7.4.3 The Module-Augmentation Pattern

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var singleton = function(){

//private variables and functions
var privateVariable = 10;
function privateFunction(){
return false;
}
//create object
var object = new CustomType();

//add privileged/public properties and methods
object.publicProperty = true;
object.publicMethod = function(){
privateVariable++;
return privateFunction();
};

//return the object
return object;
}();

Chapter8 BOM(Browser Object Model)

Provides objects that expose browser functionality independent of any web page content

8.1 THE WINDOW OBJECT

Dual purpose:

  1. JavaScript interface to the browser window
  2. ECMAScript Global object

8.1.1 The Global Scope

1
2
3
4
5
var age = 19;
window.color = 'blue';

delete window.age; // fail
delete window.color; // success
  • Cannot delete window.age: properties of window that were added via var statements have their [[Configurable]] attribute set to false

  • Attempting to access an undeclared variable throws an error, but it is possible to check for the existence of a potentially undeclared variable by looking on the window object.

    1
    2
    var newValue = oldValue;        // err
    var newValue = window.oldValue; // undefined

8.1.2-8.1.7 Window Relationships and Frames

Category Name Description
Frames frames[0] access to window object for different frame
top the very top (outermost) frame, which is the browser window itself
parent The parent object always points to the current frame’s immediate parent frame
Window Position screenLeft
screenTop
moveTo()
moveBy()
Window Size innerWidth
innerHeight
outerWidth
outerHeight
resizeTo()
resizeBy()
Navigating and Opening Windows open()
close()
Intervals and Timeouts setTimeout()
clearTimeout()
setInterval()
clearInterval()
System Dialogs alert()
confirm()
promp()
print() print dialog
find() search dialog

8.2 THE LOCATION OBJECT

  • It provides information about the document
  • window.location === document.location

Location Attributes

https://movie.douban.com/subject/1291561/?from=showing as example

Category Name Description
hash “” The URL hash or an empty string if the URL doesn’t have a hash.
host “movie.douban.com”
href “https://movie.douban.com/subject/1291561/?from=showing"
pathname “/subject/1291561/“
port “”
protocol “https:” The protocol used by the page. Typically “http:” or “https:”.
search “?from=showing” search string which start with ?

Manipulating the Location

Name Description
location.assign("http://www.wrox.com");
window.location = "http://www.wrox.com"
location.href = "http://www.wrox.com" location.search = "?q=javascript";
location.hostname = "www.yahoo.com";
…
location.replace("http://www.wrox.com") user cannot click back button to the previous page
location.reload()

8.3 THE NAVIGATOR OBJECT

For providing browser information

8.4 THE SCREEN OBJECT

An indication of client capabilities

8.5 THE HISTORY OBJECT

represents the user’s navigation history

Name Description
history.go(-1) go back one page
history.go(1) go forward one page
history.go("wrox.com") go to nearest wrox.com page
history.forward() same as history.go(1)
history.back() same as history.go(-1)

Chpater9 Client Detection

9.1 Capability detection

Tests for specific browser capabilities before using them

9.3 Quirks detection

Quirks are essentially bugs in browser implementations

9.3 User-agent detection

Detecting information about the browser, often including the browser, platform, operating system, and browser version.

Chapter10 DOM(Document Object Model)

Represents a document as a hierarchical tree of nodes, allowing developers to add, remove, and modify individual parts of the page.

10.1 HIERARCHY OF NODES

10.1.1 The Node Type

  • Node.ELEMENT_NODE (1)
  • Node.ATTRIBUTE_NODE (2)
  • Node.TEXT_NODE (3)
  • Node.CDATA_SECTION_NODE (4)
  • Node.ENTITY_REFERENCE_NODE (5)
  • Node.ENTITY_NODE (6)
  • Node.PROCESSING_INSTRUCTION_NODE (7)
  • Node.COMMENT_NODE (8)
  • Node.DOCUMENT_NODE (9)
  • Node.DOCUMENT_TYPE_NODE (10)
  • Node.DOCUMENT_FRAGMENT_NODE (11)
  • Node.NOTATION_NODE (12)

var someNode = document.getElementById('xx')

nodeName and nodeValue

Name usage Description
nodeType someNode.nodeType === Node.ELEMENT_NODE
nodeName someNode.nodeName === 'DIV' tag
childNodes someNode.childNodes[0]
someNode.childNodes.item(1)
Each node has a childNodes property containing a NodeList obj
Changes will be reflected in NodeList objects automatically (dynamic)
parentNode someNode.parentNode
previousSibling someNode.previousSibling
nextSibling someNode.nextSibling
firstChild someNode.firstChild
lastChild someNode.lastChild
appendChild someNode.appendChild(newNode)
insertBefore someNode.insertBefore(newNode, aChildNode) if null, become last node
replaceChild someNode.replaceChild(newNode, aChildNode)
cloneNode someNode.cloneNode(true) boolean: copy all children or not
normalize …

10.1.2 The Document Type

  • Represents document nodes
  • The document object in browser is an instance of HTMLDocument
  • The document object is a property of window and is accessible globally
Category Usage Description
Document Childre document.documentElement <html>
document.body <body>
document.doctype <!DOCTYPE>
Document Information
document.title
document.URL
document.domain
document.referrer gives the URL of the page that linked to this page
Locating Elements getElementById() return the first occurance
document.getElementByTagName() return a HTMLCollection obj, dynamic
images.namedItem("myImage") or images["myImage"]
parameter can be ‘*”
document.getElementByName() similar as getElementByTagName
Special Collections document.anchors Contains all \ elements with a name attribute
document.forms <form>
document.images <img>
document.links Contains all \ elements with an href attribute
DOM Conformance Detection document.implementaion.hasFeature(‘XML’’, ‘1.0’)
Document Writing write()
document.writeln()
document.open()
document.close()

10.1.3 The Element Type

Name Description
element.getAttribute() custom attributes should be prepended with data- in order to validate
element.setAttribute()
element.removeAttribute()
element.attributes .getNamedItem(name)
.removeNamedItem(name)
.setNamedItem(node)
.item(pos)
document.createElement() createElement("div");div.id="newDiv" or createElement("\<div id=\\"newDiv\\"\>\<div>");

10.1.4 The Text Type

Category Name Description
text manipulation appendData(text)
deleteData(offset, count)
insertData(offset, count)
replaceData(offset, count, text)
splitText(offset)
substringData(offset, count)
create text node createTextNode(“text”)
normalize text nodes element.normalize() it is possible to have multiple text nodes as children
split text nodes element.firstChild.splitText(5)

10.1.5 The Comment Type

  • Inherits from the same base as the Text type, so it has all of the same string- manipulation methods except splitText()
  • document.createComment()

10.1.6 The CDATASection Type

  • CDATA sections are specific to XML-based documents
  • document.createCDataSection()

10.1.7 The DocumentType Type

  • document.doctype.name === 'HTML'
  • e.g. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN": HTML

10.1.8 The DocumentFragment Type

Adding each item directly to the element causes the browser to re-render the page with the new information. It solves this issue.

1
2
3
4
5
6
7
8
9
var fragment = document.createDocumentFragment(); 
var ul = document.getElementById("myList");
var li = null;
for (var i=0; i < 3; i++){
li = document.createElement("li");
li.appendChild(document.createTextNode("Item " + (i+1)));
fragment.appendChild(li);
}
ul.appendChild(fragment);

10.1.9 The Attr Type

Not recommended.
Another way of get/set/removeAttribute().

10.2 WORKING WITH THE DOM

10.2.1 Dynamic Scripts

1
2
3
4
5
6
function loadScript(url){
var script = document.createElement("script");
cript.type = "text/javascript";
script.src = url; // or script.appendChild(document.createTextNode("function sayHi(){alert(‘hi’);}"));
document.body.appendChild(script);
}

10.2.2 Dynamic Styles

1
2
3
4
5
6
7
8
function loadStyles(url){
var link = document.createElement("link");
link.rel = "stylesheet";
link.type = "text/css";
link.href = url;
var head = document.getElementsByTagName("head")[0]; //or style.appendChild(document.createTextNode("body{background-color:red}"));
head.appendChild(link);
}

10.2.3 Manipulating Tables

Skip, I guess no one do this by hand

10.2.4 Using NodeLists

NodeList, NamedNodeMap and HTMLCollection are similar: all dynamic

  • Since a query is run against the document each time, try to cache frequently used values retrieved from a NodeList. e.g.

    1
    2
    var divs = document.getElementsByTagName('div'); 
    var len = divs.length;

Chapter11 DOM Extensions

11.1 SELECTORS API

Category Example Description
querySelector() document.querySelector(“body”) “body”, “#myId”, “.myClass”
return first element
querySelectorAll() document.querySelectorAll(“. myClass”); return NodeList obj
matchesSelector() document.body.matchesSelector("body.page1") === true

11.2 ELEMENT TRAVERSAL

Category Example
childElementCount number of child elements
firstElementChild
lastElementChild
previousElementSibling
nextElementSibling
1
2
3
4
5
6
var i, len,
child = element.firstElementChild;
while(child != element.lastElementChild){
processChild(child);
child = child.nextElementSibling;
}

11.3 HTML 5

Category Name Description
Class-Related Additions getElementsByClassName() return NodeList
classList.add(value)
.contains(value)
.remove(value)
.toggle(value)
Focus Management document.activeElement contains a pointer to the DOM element that currently has focus
element.focus()
document.hasfocus() determine if the user is interacting with the page
Changes to HTMLDocument document.readyState loading: The document is loading
complete: The document is completely loaded
document.compatMode CSS1Compat: standard
BackCompat: quirks mode
document.head
Character Set Properties document.charset “UTF-16”
Custom Data Attributes element.dataset customed data attributes should begin with “data-“, then can be fetched by element.dataset.myname; <div id="myDiv" data-myname="Nicholas"></div>
Markup Insertion innerHTML return the HTML representing all of the child nodes
outerHTML all innerHTML and it self
insertAdjacentHTML(position, text) position = [“beforebegin”, “afterbegin”, “beforeend”, “afterend”]
scrollIntoView scrollIntoView(boolean) make sure an element is visible

11.4 PROPRIETARY EXTENSIONS

Name Description
document.documentMode determines which features it has access
document.documentElement.contains(document.body)
document.documentElement.compareDocumentPosision(another) 1, 2, 4, 8 16
innerText read/write all children text content
outerText read all children text content, write all children including itself


scrollIntoViewIfNeeded() Scrolls only if it’s not already visible
scrollByLines(lineCount)
scrollByPages(pageCount)

Chapter12 DOM Levels 2 and 3

12.1 DOM CHANGES

12.1.1 XML Namespaces

Skip. I think it is gradually replaced by json

12.1.2 Other Changes

Changes to DocumentType

1
2
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"
[<!ELEMENT name (#PCDATA)>]>
  • publicId: “-//W3C//DTD HTML 4.01//EN”,
  • systemId: “http://www.w3.org/TR/html4/strict.dtd",
  • internalSubset: “<!ELEMENT name (#PCDATA)”

Changes to Document

Name Description
importNode(oldNode, boolean) Similar as cloneNode()
boolean: if copy children
document.implementaion createDocumentType()
createDocument()
createHTMLDocument()

Changes to Node

Name Description
element.isSameNode() same reference
element.isEqualNode() same attributes
element.setUserData(key, value, operationCallback) whenever the node with the data is cloned, removed, renamed, or imported into another document
element.getUserData(key)

Changes to Frames

This property contains a pointer to the document object representing the contents of the frame.

document.getElementById("frameId").contentDocument

12.2 STYLES

12.2.1 Accessing Element Styles

Any HTML element that supports the style attribute also has a style property exposed in JavaScript

CSS PROPERTY JAVASCRIPT PROPERTY
background-image element.style.backgroundImage
color element.style.color
display element.style.display
font-family element.style.fontFamily

Some attributes/methods

  • cssText
    • myDiv.style.cssText = "width: 25px;"
  • length
  • parentRule
  • getPropertyCSSValue(propertyName)
  • getPropertyPriority(propertyName)
  • getPropertyValue(propertyName)
  • item(index)
  • removeProperty(propertyName)
  • setProperty(propertyName, value, priority)
  • getComputedStyle()
    • get the actual style after overriding

12.2.2 Working with Style Sheets

CSS Style Sheets

  • CSSStyleSheet extends StyleSheet
  • Access by: document.styleSheets
  • Attributes:
    • disabled
    • href
    • media
    • ownerNode
    • parentStyleSheet
    • title
    • type
    • cssRule
    • ownerRule
    • deleteRule(index)
    • insertRule(rule, index)

CSS Rules

  • CSSStyleRule extends CSSRule
  • Access by: document.styleSheets[0].cssRule
  • Attributes

    • cssText
    • parentRule
    • parentStyleSheet
    • selectorText
    • style
    • type
  • Operations:

    • sheet.insertRule(ruleText, insertIndex)
    • sheet.deleteRule(index)

12.2.3 Element Dimensions

Category Function Description
offset dimension offsetHeight
offsetWidth
offsetLeft
offsetTop
Client Dimensions clientWidth
clientHeight
Scroll dimension scrollHeight
scrollWidth
scrollLeft
scrollTop
Element location getBoundingClientRect().left/right/top/bottom location of the element on the page relative to the viewport

OffsetDimension
ClientDimension
ScrollDimension

12.3 TRAVERSALS

Depth-first: NodeIterator, TreeWalker

12.3.1 NodeIterator

document.createNodeIterator(root, whatToShow, filter, entityReferenceExpansion)

  • root: search root
  • whatToShow: A numerical code indicating which nodes should be visited
  • filter: instance of NodeFilter.

    • var iterator = NodeFilter.SHOW_ALL
    • var iterator = NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT
    • an obj contained function acceptNode

      1
      2
      3
      4
      5
      var filter = {
      acceptNode: function(node){
      return node.tagName.toLowerCase() == "p" ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;
      }
      };
    • a function:

      1
      2
      3
      4
      5
              var filter = function(node){
      return node.tagName.toLowerCase() == "p" ?
      NodeFilter.FILTER_ACCEPT :
      NodeFilter.FILTER_SKIP;
      };
  • entityReferenceExpansion: not useful

  • The two primary methods of NodeIterator

    • nextNode()
    • previousNode()

12.3.2 TreeWalker

An advanced version of NodeIterator
document.createTreeWalker(root, whatToShow, filter, entityReferenceExpansion)

methods:

  • nextNode()
  • previousNode()
  • parentNode()
  • firstChild()
  • lastChild()
  • nextSibling()
  • previousSibling()

12.4 RANGES

12.4.1 Ranges in the DOM

  • Usage:

    • document.createRange()
  • Attributes:

    • startContainer
    • startOffset
    • endContainer
    • endOffset
    • commonAncestorContainer

Simple Selection

  • selectNode(): contain node itself
  • selectNodeContents(): only contain children

    • Usage:

      1
      2
      3
      4
      5
      var range1 = document.createRange(), 
      range2 = document.createRange(),
      p1 = document.getElementById("p1");
      range1.selectNode(p1);
      range2.selectNodeContents(p1);
  • setStartBefore(refNode)

  • setStartAfter(refNode)
  • setEndBefore(refNode)
  • setEndAfter(refNode)

Complex Selection

  • range.setStart()
  • range.setEnd()

Interacting with DOM Range Content

  • range.deleteContents()
  • range.extractContents()
  • range.cloneContents()
  • range.insertNode()
  • range.surroundContents()
  • range.collapse(): not useful
  • range1.compareBoundaryPoints(range2)
    • check if shared boundary
    • It returns
      • Range.START_TO_START: 0
      • Range.START_TO_END: 1
      • Range.END_TO_END: 2
      • Range.END_TO_START: 3
  • range.cloneRange()
  • range.detach(); range = null;: detach from document then dereferenced

12.4.2 Ranges in Internet Explorer 8 and Earlier

Skip

Chapter13 Events

13.1 Events Flow

Example:

1
2
3
4
5
6
7
8
9
<!DOCTYPE html> 
<html>
<head>
<title>Event Bubbling Example</title>
</head>
<body>
<div id="myDiv">Click Me</div>
</body>
</html>

DOM Level 2 Events has three phases

  • the event capturing phase
  • at the target
  • the event bubbling phase

EventCapture

13.2 EVENT HANDLERS

  • event name: e.g. click, load
  • event handler: e.g. onclick, onload

13.2.1 HTML Event Handlers

  • <input type="button" value="Click Me" onclick="alert(‘Clicked’)" />
  • It tightly couples the HTML to the JavaScript

13.2.2 DOM Level 0 Event Handlers

  • One method:

    • Assign a function to an event handler property, which run winthin the scope of element

      1
      2
      3
      4
      5
      6
      var btn = document.getElementById("myBtn"); 
      btn.onclick = function(){
      alert("Clicked");
      };

      btn.onclick = null; //remove event handler

13.2.3 DOM Level 2 Event Handlers

  • Two methods:
    • addEventListener(eventName, handler, captureOrBubble)
    • removeEventListener(eventName, handler, captureOrBubble)
  • multiple event handlers can be added
    • e.g. btn can have two click event
    • event fire in the order of adding order
  • event added by addEventListener can only be removed by removeEventListener with same arguments. (anonymous function… haha)

13.2.4 Internet Explorer Event Handlers

Skip

13.2.5 Cross-Browser Event Handlers

Skip

13.3 THE EVENT OBJECT

When an event related to the DOM is fired, all of the relevant information is gathered and stored on an object called event

1
2
3
btn.onclick = function(event){
alert(event.type); //"click"
};

13.3.1 The DOM Event Object

attribute type description
bubbles Boolean if the event bubbles
cancelable Boolean if the default behavior of the event can be canceled.
currentTarget Element The element whose event is handlering
defaultPrevented Boolean indicates that preventDefault() has been called
detail Integer
eventPhase Integer 1: capturing phase, 2: at target, 3: bubbling
preventDefault() Function Cancels the default behavior for the event
stopImmediatePropagation() Function Cancels any further event capturing or event bubbling and prevents any other event handlers from being called
stopPropagation() Function Cancels any further event capturing or event bubbling
target Element The target of the event.
trusted Boolean
type String The type of event that was fired
view AbstractView
  • currentTarget vs target vs this

    • currentTarget === this
    • currentTarget indicates where the handler is
    • target indicates where the action happens

      1
      2
      3
      4
      5
      document.body.onclick = function(event){
      alert(event.currentTarget === document.body); //true
      alert(this === document.body); //true
      alert(event.target === document.getElementById("myBtn")); //true
      };
  • Any event that can be canceled using preventDefault() will have its cancelable property set to true

13.3.2 The Internet Explorer Event Object

Skip

13.3.3 The Cross-Browser Event Object

Skip

13.4 EVENT TYPES

DOM Level 3 Events specifies the following event groups:

  • User interface (UI) events
    • DOMActive: deprecated
    • load: after completely loaded
      • window, script, img, body
    • unload
    • abort: Fires on an \<object> element if it is not fully loaded before the user stops the download process
    • error
    • select
    • resize
    • scroll
  • Focus events
    • blur: Fires when an element has lost focus.
    • DOMFocusIn: deprecated
    • DOMFocusOut: deprecated
    • focus — Fires when an element has received focus
    • focusin — Fires when an element has received focus
    • focusout — Fires when an element has lost focus.
    • When focus is moved from one element to another on the page, the following order of events is followed:
      1. focusout fires on the element losing focus.
      2. focusin fires on the element receiving focus.
      3. blur fires on the element losing focus.
      4. DOMFocusOut fires on the element losing focus.
      5. focus fires on the element receiving focus.
      6. DOMFocusIn fires on the element receiving focus.
  • Mouse events
    • click
    • dblclick
    • mousedown
    • mouseenter
    • mouseleave
    • mousemove
    • mouseout
    • mouseover
    • mouseup
  • Wheel events
    • mousewheel
  • Text events
    • text input
  • Keyboard events
    • keydown
    • keypress
    • keyup
  • Composition events: When inputting characters: like Chinese, Japanese
  • Mutation events: when a change occurs to the underlying DOM structure.
    • DOMSubtreeModified
    • DOMNodeInserted
    • DOMNodeRemoved
    • DOMNodeInsertedIntoDocument
    • DOMNodeRemovedFromDocument
    • DOMAttrModified
    • DOMCharacterDataModified
  • Mutation name events: when element or attribute names are changed

HTML5 Events

  • contextmenu: the menu when right mouse click
  • beforeunload: prevent the page from being unloaded.
  • DOMContentLoaded: fires as soon as the DOM tree is completely formed and without regard to images, JavaScript files, CSS files, or other such resources.
  • readystatechange: IE
  • pageshow/pagehide:
    • back-forward cache speed up page load, while won’t fire load event
    • pageshow fires after the load event or page restored
  • hashchange: when the URL hash (everything following a pound sign (#) in a URL) changed

Device Events: Skip

Touch and Gesture Events: Skip

13.5 MEMORY AND PERFORMANCE

13.5.1 Event Delegation

Basic idea: gather all same event handler in document

1
2
3
4
5
6
7
8
9
10
11
12
EventUtil.addHandler(list, "click", function(event){ 
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
switch(target.id){
case "goSomewhere":
location.href = "http://www.wrox.com";
break;
case "sayHi":
alert("hi");
break;
}
});
  • The document object is immediately available and can have event handlers assigned at any point during the page’s life cycle
  • Less time is spent setting up event handlers on the page. Assigning one event handler takes fewer DOM references and less time.
  • Lower memory usage is required for the entire page, improving overall performance.

13.5.2 Removing Event Handlers

  • Dangling event handlers: the event handler remains attached even the element is removed
  • Solution: remove event handler btn.onclick = null;

13.6 SIMULATING EVENTS

13.6.1 DOM Event Simulation

Create event by JavaScript

  • UIEvents
  • MouseEvents
  • MutationEvents
  • HTMLEvents

13.6.2 Internet Explorer Event Simulation

Skip

Chapter14 Scripting Forms

14.1 Form Basics

by the

element in HTML and by the HTMLFormElement type in JavaScript. The HTMLFormElement type inherits from HTMLElement

attribute description
acceptCharset The character sets that the server can process
action URL
elements An HTMLCollection of all controls in the form.
enctype The encoding type of the request
length number of controls in the form
method type of HTTP request. e.g. “get” “post”
name form name
reset() reset all fields to default
submit() submit form
target The name of the window to use for sending the request and receiving the response

document.forms[0] or document.forms[1]

14.1.1 Submitting Forms

any \<input> \<button> with type="submit" can submit form

form.addEventListener(‘submit’, handler);
event.preventDefault(event)
form.submit()

14.1.2 Submitting Forms

form.addEventListener(‘reset’, handler);
event.preventDefault(event)
form.reset()

14.1.3 Form Fields

form.elements[0]
form.elements[‘text1’]
form.elements.length

Common Form-Field Properties

disabled |
form | pointer to this form
name | name
readOnly
tabIndex | tab order
type | checkbox, radio …
value | if file: readonly and contain file path

Common Form-Field Methods

focus() | sets the browser’s focus to the form fi eld
autofocus | <input type="text" autofocus>
blur() | remove focus from element

Common Form-Field Events

blur | lose focus
change | lose focus and value changed for \<input> \<textarea> \<select>
focus | get focus

14.2 SCRIPTING TEXT BOXES

texBox.value = "some new value";: DO NOT use standard DOM methods(setAttribute…)

category name description
selection textbox.select() select all text when getting focus
selectionStart
selectionEnd
textbox.value.substring(textbox.selectionStart, textbox.selectionEnd)
setSelectionRange(startIndex, endIndex)
filter addHandler(“keypress”, func) combine keypress and preventDefault
Clipboard beforecopy
copy
beforecut
cut
beforepaste
paste
event.clipboardData.getData("text")
event.clipboardData.clearData()
event.clipboardData.setData("text", "abcd")
HTML5 Constraint Validation required
type=”email”
type=”url”
input types
type=”number” (range, datetime, datetime-local, date, month, week, time)
input.setUp(5)
input.setDown(5)
numeric ranges
checkValidity() input.checkValidity()
input.validity validation info
novalidate <form method="post" novalidate>

14.3 SCRIPTING SELECT BOXES

select element methods

method description
add(newOption, relOption) add newOption before relOption
multiple if multiple selection allowed boolean
options An HTMLCollection of <option> elements
remove(index)
selectedIndex
size

option element methods

method description
index
label
selected boolean
text
value

14.4 FORM SERIALIZATION

How serialize?

  • Read through all fields then encode it as “name=abc&age=14&phone=123”
  • new FormData()

14.5 RICH TEXT EDITING

Skip

Chapter15 Graphics with Canvas

Skip

Chapter 16 HTML5 Scripting

16.1 CROSS-DOCUMENT MESSAGING (XDM)

Definition: the ability to pass information between pages from different origins
e.g. www.wrox.com wants to communicate with a page from p2p.wrox.com

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//sender
//data: data
//origin: the origin of the document that sent the message
//source: A proxy for the window object of the document that sent the message
postMessage(data, origin, source)

//receiver

EventUtil.addHandler(window, "message", function(event){
//ensure the sender is expected
if (event.origin == "http://www.wrox.com"){
processMessage(event.data);
//optional: send a message back to the original window
event.source.postMessage("Received!", "http://p2p.wrox.com");
}

});

16.2 NATIVE DRAG AND DROP

  • Drag-and-Drop Events

    • dragstart
    • drag
    • dragend
  • Dragged over a valid drop target

    • dragenter
    • dragover
    • dragleave
    • drop
  • The dataTransfer Object

Attribute Description
event.dataTransfer.getData()
event.dataTransfer.setData()
======================== ==============================
event.dataTransfer.dropEffect which type of drop behaviors are allowed [‘none’, move’, ‘copy’, ‘link’]
event.dataTransfer.effectAllowed which dropEffect is allowed for the dragged item
======================== ==============================
event.dataTransfer.addElement(element) Adds an element to the drag operation
event.dataTransfer.clearData(format)
event.dataTransfer.setDragImage(element, x, y) Allows you to specify an image to be displayed under the cursor as the drag takes plac
event.dataTransfer.types A list of data types currently being stored
graggable <img src="smile.gif" draggable="false">

16.3 MEDIA ELEMENTS

Two new tag: \<video> \<audio>

Tag Attribute
src media source
poster an image URI to display while the video content is being loaded
controls display a UI component

Properties:

  • autoplay, buffered, bufferedBytes, bufferingRate, bufferingThrottled,
    controls, currentLoop, currentSrc, currentTime, defaultPlaybackRate,
    duration, ended, loop, muted, networkState,
    paused, playbackRate, played, readyState, seekable,
    seeking, src, start, totalBytes, videoHeight, videoWidth,
    volume,
  • abort, canplay, canplaythrough, canshowcurrentframe, dataunavailable,
    durationchange, emptied, empty, ended, error,
    load, loadeddata, loadedmetadata, loadstart, pause,
    play, playing, progress, ratechange, seeked,
    seeking, stalled, timeupdate, volumechange, waiting

Methods:

  • element.play()
  • element.pause()
  • element.canPlayType(): return true/false
  • Audio(): var audio = new Audio()

16.4 HISTORY STATE MANAGEMENT

Issue: sometimes I open a new dialog by js and wanna close it by the Back button

1
2
3
4
5
6
7
8
9
10
11
// push state into history
history.pushState(data, title, URL)

// happens when clicking `Back` button
window.addEventListener("popState", function(event) {
let state = event.popState; // null if no history
processState(state);
}

// overwrite current state
history.replaceState(data, title, URL);

Chapter17 Error Handling and Debugging

17.1 BROWSER ERROR REPORTING

Skip: Introduce Developer Tool

17.2 ERROR HANDLING

17.2.1 try-catch-finally

Error Types
Error base type
EvalError exception when eval()
RangeError number is outside the bounds of its range
ReferenceError attempting to access a variable that doesn’t exist
SyntaxError
TypeError
URIError encodeURI() or decodeURI()

17.2.2 Throwing Errors

1
2
3
4
5
6
// all legal
throw 12345;
throw "Hello world!";
throw true;
throw { name: "JavaScript"};
throw new SyntaxError("I don’t like your syntax.")

customized error

1
2
3
4
5
6
function CustomError(message){ 
this.name = "CustomError";
this.message = message;
}
CustomError.prototype = new Error();
throw new CustomError("My message");

When?

  • A good error-handling protocol ensures that the only errors that occur are the ones that you throw
  • e.g.
1
2
3
4
5
6
7
8
9
10
11
12
13
function process(values){
if (!(values instanceof Array)){
throw new Error("process(): Argument must be an array.");
}
values.sort();

for (var i=0, len=values.length; i < len; i++){
if (values[i] > 100){
return values[i];
}
}
return -1;
}

17.2.3 The error Event

Error even has event !!!

1
2
3
window.onerror = function(message, url, line){ 
alert(message);
};

17.2.4 Error-Handling Strategies

17.2.5 Identify Where Errors Might Occur

  • Type coercion errors
  • Data type errors
  • Communication errors

17.2.6 Distinguishing between Fatal and Nonfatal Errors

17.2.7 Log Errors to the Server

Soooooo smart. Each image will visit its url.

1
2
3
4
5
function logError(sev, msg){
var img = new Image();
img.src = "log.php?sev=" + encodeURIComponent(sev) + "&msg=" +
encodeURIComponent(msg);
}

17.3 DEBUGGING TECHNIQUES

17.3.1 Logging Messages to a Console

  • error(message)
  • info(message)
  • log(message)
  • warn(message)

17.3.2 Logging Messages to the Page

never mind

17.3.3 Throwing Errors

  • throw new Error(xxx);
  • assert(condition, msg)

17.4 COMMON INTERNET EXPLORER ERRORS

Skip

Chapter18 XML in JavaScript

Skip

Chapter19 ECMAScript for XML

Skip

Chapter20 JSON

20.1 SYNTAX

type example
Simple Values “Hello World”
Object {“name”: “Nicholas”, “age”: 29}
Arrays [{..}, {..}]

20.2 PARSING AND SERIALIZATION

20.2.1 The JSON Object

Method Convert
JSON.stringify() object -> JSON string
JSON.parse() JSON string -> object

20.2.2 Serialization Options

  • Filtering Results

    1
    2
    3
    4
    5
    JSON.stringify(object, ["title", "edition"])
    JSON.stringify(object, function(key, value){
    if (key === "xxx") {return undefined;}
    return value;
    }
  • String Indentation

    JSON.stringify(object, null, 4); // indent as 4

  • The toJSON() Method

    • define a toJSON() method in object. e.g.

      1
      2
      3
      4
      5
      6
      var book = {"name":"Nicholas", 
      "age":16,
      toJSON:function() {
      return this.name;
      }}
      JSON.stringify(book); // only stringify Simple Value name

20.2.3 Parsing Options

1
2
3
4
5
6
7
8
9
var bookCopy = JSON.parse(jsonText, function(key, value){
if (key == "releaseDate"){
return new Date(value);
} else if (key == "name") {
return undefined; // skip this pair
} else {
return value;
}
});

Chapter21 Ajax and Comet

The key technology pushing Ajax forward was the XMLHttpRequest (XHR) object

21.1 THE XMLHttpRequest OBJECT

21.1.2 XHR Usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var xhr = new XMLHttpRequest();

xhr.onreadystatechange = function(){
if (xhr.readyState == 4){
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
}
};

xhr.open("get", "example.txt", false); // GET/POST, URI, isAsynchronous
xhr.send(null);

You can access only URLs that exist on the same origin, which means the same domain, using the same port, and with the same protocol.

readyState description
0 Uninitialized. The open() method hasn’t been called yet.
1 Open. The open() method has been called but send() has not been called.
2 Sent. The send() method has been called but no response has been received.
3 Receiving. Some response data has been retrieved.
4 Complete. All of the response data has been retrieved and is available.
attribute description
responseText The text that was returned as the body of the response.
responseXML Contains an XML DOM document with the response data if the response has a content type of “text/xml” or “application/xml” .
status The HTTP status of the response.
statusText The description of the HTTP status.

21.1.3 HTTP Headers

1
2
3
xhr.open("get", "example.php", true);
xhr.setRequestHeader("MyHeader", "MyValue");
xhr.send(null);
  • Accept
  • Accept-Charset
  • Accept-Encoding
  • Accept-Language
  • Connection
  • Cookie
  • Host
  • Referer
  • User-Agent

21.1.4 GET Requests

1
2
3
4
5
6
7
8
9
10
xhr.open("get", "example.php?name1=value1&name2=value2", true);		// wrong

// should be encoded
function addURLParam(url, name, value) {
url += (url.indexOf("?") == -1 ? "?" : "&");
url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
return url;
}

url = addURLParam(url, 'name', 'Ni');

21.1.5 POST Requests

1
2
3
4
xhr.open("post", "postexample.php", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
var form = document.getElementById("user-info");
xhr.send(serialize(form));
  1. set header
  2. serialize form

21.2 XMLHttpRequest LEVEL 2

21.2.1 FormData

1
2
3
4
5
6
7
var data = new FormData();

var data = new FormData(document.forms[0]);

data.append("name", "Nicholas");

xhr.send(data);

21.2.2 Timeouts

1
2
3
4
5
6
xhr.open("get", "timeout.php", true);
xhr.timeout = 1000; //set timeout for 1 second (IE 8+ only)
xhr.ontimeout = function(){
alert("Request did not return in a second.");
};
xhr.send(null);

21.2.3 overrideMimeType()

The returned MIME type for a response determines how the response is handled by the XHR objec

1
2
3
4
var xhr = createXHR();
xhr.open("get", "text.php", true);
xhr.overrideMimeType("text/xml");
xhr.send(null);

21.3 PROGRESS EVENTS

event description
loadstart Fires when the fi rst byte of the response has been received.
progress Fires repeatedly as a response is being received. lengthComputable, position, totalSize
error Fires when there was an error attempting the request.
abort Fires when the connection was terminated by calling abort() .
load Fires when the response has been fully received.
loadend Fires when the communication is complete and after fi ring error , abort , or load .

21.4 CROSS-ORIGIN RESOURCE SHARING

CORS: XHR objects can access resources only on the domain from which the containing web page originates

  • send request with extra header called Origin including (protocol, domain name, and port)
    • e.g. Origin: http://www.nczonline.net
  • If the server decides that the request should be allowed, it sends an Access-Control-Allow-Origin header echoing back the same origin that was sent or “*” if it’s a public resource
    • e.g. Access-Control-Allow-Origin: http://www.nczonline.net
1
2
3
var xhr = createXHR();
xhr.open("get", "http://www.somewhere-else.com/page/", true); // an absolute URL
xhr.send(null);
  • Preflighted Requests

    • CORS allows the use of custom headers, methods other than GET or POST, and different body content types
    • When you try to make a request with one of the advanced options, a “preflight” request is made to the server.
    • This request uses the OPTIONS method and sends the following headers

      1
      2
      3
      Origin: http://www.nczonline.net
      Access-Control-Request-Method: POST
      Access-Control-Request-Headers: NCZ
    • server should return

      1
      2
      3
      4
      Access-Control-Allow-Origin: http://www.nczonline.net
      Access-Control-Allow-Methods: POST, GET
      Access-Control-Allow-Headers: NCZ
      Access-Control-Max-Age: 1728000
  • Credentialed Requests
    • Access-Control-Allow-Credentials: true

21.5 ALTERNATE CROSS-DOMAIN TECHNIQUES

  • Image Pings

    1
    2
    3
    4
    5
    var img = new Image();
    img.onload = img.onerror = function(){
    alert("Done!");
    };
    img.src = "http://www.example.com/test?name=Nicholas";
* you can only send GET requests
* you cannot access the response text from the server.
  • JSONP

    1
    2
    3
    4
    5
    6
    7
    	function handleResponse(response){
    alert("You’re at IP address " + response.ip + ", which is in " +
    response.city + ", " + response.region_name);
    }
    var script = document.createElement("script");
    script.src = "http://freegeoip.net/json/?callback=handleResponse";
    document.body.insertBefore(script, document.body.firstChild);
    • Unsafe: you’re pulling executable code into your page from another domain
    • Hard to determine that a JSONP request has failed
  • Comet

    • long polling
    • streaming
  • Server-Sent Events

    • Client API for Comet

      1
      2
      3
      4
      5
      6
      7
      var evtSource = new EventSource("ssedemo.php");
      evtSource.onmessage = function(e) {
      var newElement = document.createElement("li");

      newElement.innerHTML = "message: " + e.data;
      eventList.appendChild(newElement);
      }
    • Server code

      1
      2
      3
      @app.route('/stream/', methods=['GET', 'POST'])
      def stream():
      return Response(event(), mimetype="text/event-stream") # MIME type
  • Web Sockets

    • Must use a specialized server supporting the protocol to work properly
    • Client API

      • event: open, error, close, message
      • readyState

        • WebSocket.OPENING(0)
        • WebSocket.OPEN(1)
        • WebSocket.CLOSING(2)
        • WebSocket.CLOSE(3)
        1
        2
        3
        4
        5
        6
        7
        8
        var socket = new WebSocket("ws://www.example.com/server.php");
        socket.send(JSON.stringify(message));

        socket.onmessage = function(event) {
        var data = event.data;
        }

        socket.close()

21.5.6 SSE versus Web Sockets

  • SSE

    • base on HTTP protocol
    • easier to implement
    • one direction
  • Web Sockets

    • base on Web Socket protocol
    • bidirection

21.6 SECURITY

  • Requiring SSL to access resources that can be requested via XHR.
  • Requiring a computed token to be sent along with every request.

Chapter22 Advanced Techniques

22.1 ADVANCED FUNCTIONS

22.1.1 Safe Type Detection

Issue:

The instanceof operator does not work when multiple global scopes are present, such as when there are multiple frames. e.g.var isArray = value instanceof Array;

Solution:

1
2
3
function isArray(value){
return Object.prototype.toString.call(value) == "[object Array]";
}

22.1.2 Scope-Safe Constructors

1
2
3
4
5
6
7
function Person(name, age, job){
if (this instanceof Person){
this.name = name; this.age = age; this.job = job;
} else {
return new Person(name, age, job);
}
}

22.1.3 Lazy Loading Functions

  • manipulating the function the first time it is called

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function createXHR(){
    if (typeof XMLHttpRequest != "undefined"){
    createXHR = function(){ // override the function
    return new XMLHttpRequest();
    };
    }
    else {
    createXHR = function(){ // override the function
    throw new Error("No XHR object available.");
    };
    }
    return createXHR(); // next time the function is already decided
    }
  • assign the appropriate function immediately when the function is declared

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var createXHR = (function(){
    if (typeof XMLHttpRequest != "undefined"){
    return function(){
    return new XMLHttpRequest();
    };
    }
    else {
    return function(){
    throw new Error("No XHR object available.");
    };
    }
    })();

22.1.4 Function Binding

see 5.5.5

22.1.5 Function Currying

Creates functions that have one or more arguments already set (also called partial function application

1
2
3
4
5
6
7
8
var handler = {
message: "Event handled",
handleClick: function(name, event){
alert(this.message + ":" + name + ":" + event.type);
}
};
var btn = document.getElementById("my-btn");
EventUtil.addHandler(btn, "click", bind(handler.handleClick, handler, "my-btn"));

Just like functional programming

22.2 TAMPER-PROOF OBJECTS

  • Nonextensible Objects

    • cannot add
    • Object.isExtensible(person)

      1
      2
      3
      4
      var person = { name: "Nicholas" };
      Object.preventExtensions(person);
      person.age = 29;
      alert(person.age); //undefined
  • Sealed Objects

    • cannot add/delete
    • Object.isSealed(person);

      1
      2
      3
      4
      5
      6
      7
      var person = { name: "Nicholas" };
      Object.seal(person);
      person.age = 29;
      alert(person.age); //undefined

      delete person.name;
      alert(person.name); //"Nicholas"
  • Frozen Objects

    • cannot add/delete/update
    • Ojbject.isFrozen(person)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      var person = { name: "Nicholas" };
      Object.seal(person);
      person.age = 29;
      alert(person.age); //undefined

      delete person.name;
      alert(person.name); //"Nicholas"

      person.name = "Greg";
      alert(person.name); //"Nicholas"

22.3 ADVANCED TIMERS

22.3.1 setTimeout and setInterval

  • No code is executed immediately in JavaScript; it is executed as soon as the process is idle.
  • setTimeout(func, 250) means adding func into the queue after 250mm
  • setInterval() has 2 main issues:
    • intervals may be skipped
    • intervals may be smaller than expected between multiple timer-code executions

Solution:

1
2
3
4
5
setTimeout(function(){ 
//processing
setTimeout(arguments.callee, interval);

}, interval);

22.3.2 Yielding Process

Issue:

  • There is a long-running script limit
  • If you reach that limit, the user is presented with a browser error dialog indicating that a script is taking too long to execute and asking whether the user would like to allow it to continue processing or stop.

Solution:

  • array chunking
  • create a queue of items to process, use timers to pull the next item to process, process it, and then set another timer
1
2
3
4
5
6
7
8
9
setTimeout(function(){
//get next item and process it
var item = array.shift();
process(item);
//if there’s more items, set another timeout
if(array.length > 0){
setTimeout(arguments.callee, 100);
}
}, 100);

22.3.3 Function Throttling

Issue:

  • Attempting to perform too many DOM-related operations in sequence can cause the browser to hang, and sometimes crash.

Solution:

  • The basic idea behind function throttling is that some code should not be executed repeatedly without a break
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var processor = { 
timeoutId: null,

//method that actually performs the processing
performProcessing: function(){
//actual processing code
},

//method that is called to initiate processing
process: function(){
clearTimeout(this.timeoutId);
var that = this;
this.timeoutId = setTimeout(function(){
that.performProcessing();
}, 100);
}
};
//try to start processing
processor.process();

22.4 CUSTOM EVENTS

Use the observer pattern

22.5 DRAG AND DROP

just some drag/drop event implementation code

Chapter23 Offline Applications and Client-Side Storage

23.1 OFFLINE DETECTION

  • navigator.online
  • events
    • online
    • offline

23.2 APPLICATION CACHE

  • Need a manifest file: lists out the resources to be downloaded

    • offline.appcache

      1
      2
      3
      4
      CACHE MANIFEST

      file.js
      file.css
  • The manifest file is associated with a page by specifying its path in the manifest attribute of

    <html manifest="/offline.appcache">

  • JS API

    • applicationCache.status
    • applicationCache.update()
    • applicationCache.swapCache()
    • applicationCache event
      • checking
      • error
      • noupdate
      • downloading
      • progress
      • updateready
      • cached

23.3 DATA STORAGE

23.3.1 Cookie

  • Response header:

    1
    2
    3
    4
    HTTP/1.1 200 OK
    Content-type: text/html
    Set-Cookie: name=value
    Other-header: other-header-value
  • Request header

    1
    2
    3
    GET /index.html HTTP/1.1
    Cookie: name=value
    Other-header: other-header-value
  • Restrictions
    • Cookies are, by nature, tied to a specific domain
    • Limitation of amount of cookies
    • Limitation of length of cookies
  • Cookie Parts

    • name: case insensitive, should be URL encoded
    • value: should be URL encoded
    • domain: The domain for which the cookie is valid
    • path: The path within the specified domain for which the cookie should be sent to the server
      • we can specify http://www.wrox.com/books as path, so cookie won’t be sent in https://www.wrox.com even they have the same domain
    • expiration: A time stamp indicating when the cookie should be deleted (that is, when it should stop being sent to the server
    • secure flag: cookie information is sent to the server only if an SSL connection is used.
      • https://www.wrox.com works
      • http://www.wrox.com doesn’t work
  • Cookie in JavaScript

    • document.cookie = "name=Nicholas"
      • added to the existing set of cookies instead of
      • Setting document.cookie does not overwrite any cookies unless the name of the cookie being set is already in use
  • Subcookies

    • A technique that get around the per-domain cookie limit imposed by browsers
    • format: name=name1=value1&name2=value2&name3=value3&name4=value4&name5=value5

23.3.2 Internet Explorer User Data

Skip

23.3.3 The Storage Type

Storage Object

  • methods
    • clear()
    • getItem(name)
    • key(index)
    • removeItem(name)
    • setItem(name value)
  • types
    • sessionStorage
    • globalStorage (deprecated)
    • localStorage
  • storage event
    • Whenever a change is made to a Storage object, the storage event is fired on the document
    • domain
    • key
    • newValue
    • oldValue

sessionStorage

  • Data is stored until the browser is closed
  • Data stored persists across page refreshes
  • Data available if the browser crashes and is restarted

localStorage

  • In order to access the same localStorage object, pages must be served from the same domain (subdomains aren’t valid), using the same protocol, and on the same port.
  • Data persisted until it is specifically removed via JavaScript or the user clears the browser’s cache.

23.3.4 IndexedDB

  • database in JS
  • use case
    • store large amount of data in UI
    • locate data fast
    • suppport transaction
    • offline application

Chapter24 Best Practices

  • Maintainability
  • Performance
  • Deployment

Chapter25 Emerging APIs

25.1 requestAnimationFrame()

Reason:

  1. We need to determine the best way to schedule a redraw since each browser has a fixed refresh rate. So Javascript animation can work smoothly.
  2. setInterval() and setTimeout() are inaccurate.
  3. Redrawing too often will consume too much resource.
  4. This technique asks browser to update animation on next repaint.

Implementation:

Function Description
setInterval() Deprecated because of accuracy
mozRequestAnimationFrame() Chrome: webkitRequestanimationFrame(callback, element)
IE: msRequestAnimationFrame()

25.2 Page Visibility API

Reason:

  1. Knowing when users are actually interacting with the page.

Implementation

Function Description
document.hidden A Boolean value indicating if the page is hidden from view
document.visibilityState State indicator
visibilitychange Event fires when a document changes from hidden to visible or vice versa.

25.3 Geolocation API

navigator.geolocation has 3 functions:

  1. getCurrentPosition(successCallBack, failCallback, options)
    • successCallBack: latitude, longitude, accuracy, altitude, altitudeAccuracy, heading, speed
    • options: enableHighAccuracy, timeout, maximumAge
  2. watchPosition()
  3. clearPosition()

25.4 File API

File Attributes

  • name
  • size
  • type
  • lastModifiedData

25.4.1 FileReader

Function Description
readAsText(file, encoding) store as plain text
readAsDataURL(file) store as URI
readAsBinaryString(file) store as Binary String
readAsArrayBuffer(file) store as ArrayBuffer

Asynchronously:

Event Description
progress lengthComputable, loaded, total
load
error reader.error.code: 1, 2, 3, 4

25.4.2 Partial Reads

  • Reason: Save time if read only parts of a file instead of the whole file
  • Implementation:
    • blob.slice(startByte, length)
    • reader.readAsText(blobSliceObj)

25.4.3 Object URLs

  • Reason: Don’t need to read the file contents into JavaScript in order to use them
  • Implementation:

    1
    2
    url = createObjectURL(file)
    xx.innerHTML = `<img src="${url}">`

25.4.4 Drag-and-Drop File Reading

In event handler:

  1. Cancel the default behavior of dragenter, dragover, and drop.
  2. event.dataTransfer.files

25.4.5 File Upload with XHR

1
2
3
4
5
6
(in event handler)
data = new Formdata();
xhr = new XMLHttpRequest();
...
data.append('file', event.dataTransfer.files[0]);
xhr.send(data)

25.5 Web Timing

Reason: value page performance

25.6 Web Workers

Reason: allow uds to run asynchronous JavaScript that will not block the user interface

Implementation:

  • Page:

    1
    2
    3
    4
    5
    6
    var data = [1, 2, 3, 4];
    var worker = new Worker("xx.js");
    woder.onmessage = function(event) {
    var data = event.data; // Formatted return data
    }
    worker.postmessage(data);
  • xx.js(worker):

    1
    2
    3
    4
    5
    self.onmessage = function(event) {
    var data = event.data;
    data.sort();
    self.postMessage(data);
    }
  • Other functions:

Function Description
worker.terminate() stop worker in page
self.close() stop working in xx.js
importScripts() import script in xx.js

Flask<3>--Context-Management

Posted on 2019-04-19 | Edited on 2020-01-03

Context Management

1 Storage Management

Flask support Coroutines by dict and greenlet.getcurrent, it allocates space for each greenlet and store them in a dictionary

  1. create a dictionary called __storage__
  2. set, get from __storage__ using greenlet.getcurrent as key
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
try:
from greenlet import getcurrent as get_ident
except ImportError:
try:
from thread import get_ident
except ImportError:
from _thread import get_ident

class Local(object):
__slots__ = ('__storage__', '__ident_func__')

def __init__(self):
object.__setattr__(self, '__storage__', {})
object.__setattr__(self, '__ident_func__', get_ident)

def __iter__(self):
return iter(self.__storage__.items())

def __call__(self, proxy):
"""Create a proxy for a name."""
return LocalProxy(self, proxy)

def __release_local__(self):
self.__storage__.pop(self.__ident_func__(), None)

def __getattr__(self, name):
try:
return self.__storage__[self.__ident_func__()][name]
except KeyError:
raise AttributeError(name)

def __setattr__(self, name, value):
ident = self.__ident_func__()
storage = self.__storage__
try:
storage[ident][name] = value
except KeyError:
storage[ident] = {name: value}

def __delattr__(self, name):
try:
del self.__storage__[self.__ident_func__()][name]
except KeyError:
raise AttributeError(name)

2 Request Context

  • Request context includes request and session
  • Basically, each request comes
    1. Capsulate environ into a RequestContext object
    2. Add it into __storage__ dictionary
    3. Dispatch request to each view file and do operation
    4. Remove it from __storage__ dictionary

Picture for step 1, 2, 4

RequestContext

Picture for step 3 example

Request

partial(): it is quite funcional programming
object.__setattr__(self, '_LocalProxy__local', local): stuck here for quite a while. python3 documentation

3 App Context

  • It is quite similar as Request Context
  • It includes current_app and g

Flask<2>--Dispatching-Request

Posted on 2019-04-07 | Edited on 2020-01-03

A simple Flask server

1
2
3
4
5
6
7
8
9
from flask import Flask
app = Flask(__name__)

@app.route('/') # -------------------- 2
def hello_world():
return 'Hello World!'

if __name__ == '__main__':
app.run() # ---------------------- 1

1 Flask Request Entry

This is a simple werkzeug server

1
2
3
4
5
6
7
8
9
10
from werkzeug.wrappers import Request, Response

@Request.application
def hello(request):
return Response('Hello World!')

if __name__ == '__main__':
from werkzeug.serving import run_simple
# listen to `http://localhost:4000/` and do a hello() once we visit it.
run_simple('localhost', 4000, hello)
  • app.run(): bases on werkzeug.serving.run_simple(host, port, self, **options). So once we visit its route, the entry of Flask application is app(), which is the Flask.__call__.
  • Flask.__call__: use wsgi_app
    • return self.wsgi_app(environ, start_response)
  • In the end, the real entry is wsgi_app(environ, start_response)

2 Route Register

1
2
3
@app.route('/')
def hello_world():
return 'Hello World!'

This Python Decorator is equivalant to

1
2
3
def hello_world():
return "Hello World"
app.route("/")(hello_world)
  • app.route(): base on self.add_url_rule(rule, endpoint, f, **options). It binds a function with a url. So these two are equivalant

    • app.add_url_rule("/", hello_world.__name__, hello_world)
    • app.route("/")(hello_world)
  • add_url_rule(rule, endpoint, view_func):

    • rule = self.url_rule_class(rule, methods=methods, **options): combine url, methods(post, get…), endpoint together
    • self.url_map.add(rule): this url_map is werkzeug.routing.Map
    • self.view_function[endpoint] = view_func, it binds endpoint with function and is used when dispatching request

3 Dispatching Request

From Flask Request Entry, the real request entry is wsgi_app(environ, start_response), What does it do with the Routing system ?

  1. push request_context into context
  2. Flask.dispatch_request
    • return self.view_functions[rule.endpoint](**req.view_args)

Finally, it is equal to return hello_world()

Robotframework Learning Note

Posted on 2019-03-10 | Edited on 2019-03-13

1 Getting started

3 ways of execution:

  • robot init.robot or
  • python3 robot -m init.robot or
  • python3 xx/python3.7/site-packages/robot/run.py init.robot

2 Creating test data

2.1 Test data syntax

2.1.1 Files and directories

TestSuites(a test project) contain:

Name Description
Test files contains test cases
Initialization file configure the created test suite dir
Test library lowest level keywords
Resource files variables and keywords
Variable files able to dynamically create variables, which is more flexible than resource files

2.1.2 Test data section

A test file contains:

Section Description
Settings importing test libraries, resource files and variable files, Documentation, Metadata, Suite Setup/Teardown
Variables defining variables (global to each test case)
Test cases creating test cases using keywords
Tasks
(new feature)
like test cases. a single file can only contain either test cases or task
Keywords Creating user keywords

Sometimes Section is also called table ! e.g. variable table

2.1.3 Supported file formats

html, tsv, txt, robot(recommended), rst

2.1.4 Rules for parsing the data

  • Ignore data: lots of rules, basically # is used for comment
  • Escaping: \
  • Special sequences: \n, \r, \t, \x, \u, \U
  • Some useful BuiltIn libraries. e.g. Convert To Bytes, ${\n}, ${EMPTY}, ${SPACE}
  • Multiple line: use … It is useful for keywords, documentation, variables

    1
    2
    @{LIST}    1    2    3    4
    ... 5 6

2.2 Creating test cases

2.2.1 Test cases syntax

  • Keywords can be imported from Library, Resource or keyword table
  • Each test case can have:
    • [Documentation]
    • [Tags]
    • [Setup], [Teardown]
    • [Timeout]
    • [Template]: data driven test, mentioned in 2.2.7

2.2.2 Arguments

Behaves like python:

  • Positional arguments
  • Default value arguments
  • Variable number of arguments
  • Named arguments
  • **kargs

2.2.3 Failures

  • If a test case fails, rest test cases will still run
  • We can specify failure reason e.g.
    • Should Be True ${result} xx is not true
  • Continue on failure: 3.2.2

2.2.4 Test case name and documentation

  • ${TEST_NAME} refer to the test name. More in 2.6.4 Built-in variables
  • The [Documentation] in test case shows in the command line and test reports.

2.2.5 Tagging test cases

  • –include, –exclude to run test cases
Name Location Description
Force Tags Setting table Set tags all test cases in this file. If it is in init file, all sub test suite dir are tags as it
Default Tags Setting table Set tags for test cases without [Tag]. Cannot use in init file
Tags Test Case table set tag for test case. Can override Default Tags. Can also be NONE
BuiltIn keywords Dynamically set tags: Set Tags, Remove Tags, Fail and Pass Execution keywords,

2.2.6 Test setup and teardown

  • Test Setup, Teardown can take care of only 1 task:
    • Use user defined keywords
    • Use builtIn “Run Keywords”
  • Each test case can have its own [Setup], [Teardown] to override the one in Settings
  • Detail is in 3.2.1 Execution Flow

2.2.7 Test templates

  • Convert keyword-driven test cases into data-driven tests.
  • It’s like I have a method that need to be tested for lots of pairs of different arguments and expected output.
  • Example

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    *** Test Cases ***
    Template with embedded arguments
    [Template] The result of ${calculation} should be ${expected}
    1 + 1 2
    1 + 2 3

    *** Keywords ***
    The result of ${calculation} should be ${expected}
    ${result} = Calculate ${calculation}
    Should Be Equal ${result} ${expected}

2.2.8 Different test case styles

  • Keyword-driven: normal
  • Data-driven: using template
  • Behavior-driven: using Given, When, Then, And, But
    • Given: initial state
    • When: operation
    • Then: expected result
    • And, But: connect keywords

2.3 Creating Tasks

new feature after Robotframework 3.1

2.4 Creating test suites

2.4.1 Test case files

In Setting table, we can have

  • Documentation
  • Metadata
  • Suite Setup
  • Suit Teardown

2.4.2 Test suite directories

Initialization files:

  • For specifying test suite related settings
  • Similar as test case files, but cannot have test case tables and not all settings are supported.
  • Library, resource, variable, keywords cannot applied to other files !!!

2.4.3 Test suite name and documentation

  • Test suite name
    • name is constructed from fire name
    • underscore -> space
    • e.g. some_tests.robot -> Some Tests
    • Execution order: by file name. Detail in 3.2.1 Execution flow

2.4.4 Free test suite metadata

2.4.5 Suite setup and teardown

  • Suite setup is executed before any of suite’s test cases or child test suites. Suite setup fails, all testcase fails
  • Suite teardown is executed after everything, even suite setup fails.
  • They can be set in init file

2.5 Using test libraries

2.5.1 Importing libraries

  • Library: used in Settings table
  • Import Library: used in test cases dynamically

2.5.2 Specifying library to import

  • System tries to find the library from the module search path including PYTHONPATH
  • Using relative, absolute path

    1
    2
    3
    4
    5
    *** Settings ***
    Library PythonLibrary.py
    Library /absolute/path/JavaLibrary.java
    Library relative/path/PythonDirLib/ possible arguments
    Library ${RESOURCES}/Example.class

2.5.3 Setting custom name to test library

We can initialize 2 python class using this way. e.g.

1
2
Library    xx    arg1    WITH NAME    TestLib1
Library xx arg2 WITH NAME TestLib2

2.5.4 Standard libraries

2.5.5 External libraries

2.6 Variables

2.6.1 Introduction

  • &{} dictionary
  • ${} variable
  • @{} list
  • %{} environment

2.6.2 Using variables

  • Naming rules:
    • Case insensitive, ignore underscore and space
    • Global variables naming rule: upper case
  • ${} variables

    • Can contain any object, including numbers, lists, dictionaries, or even custom objects.
    • With other string or variable, this variable will convert to its unicode | str e.g.

      1
      2
      3
      ${VAR} is an object
      Method ${VAR} # Method gets an object
      Method Hi ${VAR} # Method gets a string
  • @{} list

    • Not a true list argument !!! We should use ${} to parse a list variable as argument, since these are equivalent.

      1
      2
      3
      @{USER}    robot    secret
      Login robot secret
      Login @{USER}
    • Accessing list items

      1
      2
      3
      @{STRINGS}    one    two    kolme    four
      ${STRINGS}[2:-1:2] # Start from 2 until last one, step 2
      @{STRINGS}[index] # Old syntax. Do not use it
  • &{} dictionary

    • Not a true dictionary argument !!! We should use ${} to parse a list variable as argument, since these are equivalent.

      1
      2
      3
      &{USER}    name=robot    password=secret
      Login name=robot password=secret
      Login &{USER}
    • Accessing list items
      ${USER.name} or ${USER}[name]

  • %{} environment variables

    • Keyword: Set Environment Variable
    • Keyword: Delete Environment Variable

2.6.3 Creating variables

  1. Variable table in test case file or resource file

    • Cannot create dynamic variables
    • Syntax can be either

      1
      2
      3
      4
      ${NAME}    robot
      ${NAME} = robot
      @{LIST} one two
      &{DICT} first=one second=two
  2. Variable file

    • robot --variablefile xx.py test.robot
    • Global to all testcases
  3. Command line variables

    • robot --variable NAME:robot
    • Global to all testcases
  4. BuiltIn keywords for local variables

    1
    2
    3
    4
    5
    @{list} =    Create List    1    2
    ${list} = Create List 1 2
    ${dict} = Create Dictionary 1 2
    &{dict} = Create Dictionary 1 2
    ${a} ${b} = Create List 1 2
  1. Set Test/Suite/Global Variable keywords
    • Set Test Variable: visible in this test case
    • Set Suite Variable: visible in this test suite (all test cases in this file)
    • Set Global Variable: visible in global, like -variable

2.6.4 Built-in variables

  • Operating-system variables
    • ${CURDIR}
    • ${TEMPDIR}
    • ${EXECDIR}
    • ${/}: path separator
    • ${:}: path separator
    • ${\n}: system line separator
  • Number variables
    • int ${80}
    • float ${3.14}
    • scientific ${-1e-4}
    • binary ${0b1011}
    • octal ${0o10}
    • hex ${0xff}
  • Boolean
    • case insensitive
    • ${true} ${false}
  • Null
    • case insensitive
    • ${none} ${null}
  • Space and empty variables
    • Should Be Equal {SPACE * 4} \ \ \ \
    • ${EMPTY} @{EMPTY LIST} &{EMPTY DICT}
  • Automatic variables
    • It is like metadata of robot test
      ${TEST NAME} ${SUITE NAME} ${PREV TEST NAME} ${OUTPUT DIR}

2.6.5 Variable priorities and scopes

Priorities

  1. Variable set during test execution
    • e.g. Create List or return value
    • e.g. Set Test/Suite/Global Variable keywords
    • Highest priority
    • Cannot affect variables not in its scope
  2. –variable:
    • Second priority
    • Last one override others
    • Override all others
  3. –variablefile:
    • Third priority
    • Variable in first file override others
  4. Variable table
    • Forth priority
    • visible to all test case in this file
  5. Imported resource and variable files
    • Lowest
  6. Built-in variables
    • This is special case. I don’t think it should be discussed here

Scope

  • Global scope: –variable, –variablefile, Built-in variables, Set Global Variable
  • Test suite scope
    • Not recursive: higher-level test suite are not available in lower-level suites
    • Set Suite Variable, Imported resource and variable files, Variable table
  • Test case scope: return value from keywords

2.6.6 Advanced variable features (interesting)

  • Extended variable syntax

    • The expression inside the curly brackets is evaluated as a Python expression

      1
      2
      3
      4
      5
      6
      Keyword1    ${OBJECT.eat('Cucumber')}
      Keyword2 ${OBJECT.name}
      Keyword3 ${DICT[2]}

      ${string} = Set Variable abc
      Log ${string.upper()}
  • Extended variable syntax assignment
    ${OBJECT.name} = Set Variable New name

  • Variables inside variables

    1
    2
    3
    4
    5
    ${JOHN HOME}    /home/john
    ${JANE HOME} /home/jane

    ${name} = Get Name
    Keyword ${${name} HOME}

2.7 Creating user keywords

2.7.1 User keyword syntax

  • Keywords in init file are not visible in other files, neither files in same directory or sub-directory
  • Can only resource another file to use its keywords
  • Settings in Keyword:
    • [Documentation]
    • [Tags]
    • [Arguments]
    • [Return]
    • [Teardown]
    • [Timeout]

2.7.2 User keyword name and documentation

2.7.3 User keyword tags

2.7.4 User keyword arguments

  • Positional
  • Default values
  • Variable number of arguments

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    *** Test Cases ***
    Example
    Two Arguments With Defaults arg2=abcd
    *** Keywords ***
    One Required And One With Default
    [Arguments] ${required} ${optional}=default
    Two Arguments With Defaults
    [Arguments] ${arg1}=default 1 ${arg2}=${VARIABLE}
    Required, Default, Varargs
    [Arguments] ${req} ${opt}=42 @{others}
  • Free named arguments: like **kargs in python
    [Arguments] ${required} &{kargs}

  • Named-only arguments with user keywords
    • New feature after 3.1
    • Specify named argument after @{varargs} or after @{}
    • With Varargs
      [Arguments] @{varargs} ${named}
    • Without Varargs
      [Arguments] @{} ${named}

2.7.5 Embedding arguments into keyword name

Confused space with sequential word

  • Select ${city} ${name}
  • Select Los Angeles Lakers will be confused
  • Have to use “” to wrap it

    1
    2
    3
    4
    5
    *** Keywords ***
    Select "${city}" "${team}" from list
    Log ${city} ${team}

    Select "Los Angeles" "Lakers" from list

Embedded arguments matching rule

  • Regular expressions: every argument in the name is replaced with a pattern .*? that basically matches any string.

    • Example

      1
      2
      3
      I execute "ls" with "-lh", will match both
      I execute "${cmd}"
      I execute "${cmd}" with "${opts}"
    • Solution
      I execute "${cmd:[^"]+}"

Escaping special characters

like }, \

2.7.6 User keyword return values

  • Using [Return] setting

    1
    2
    3
    4
    5
    6
    ${a}    ${b}    ${c} =    Return Three Values
    @{list} = Return Three Values
    ${scalar} @{rest} = Return Three Values

    Return Three Values
    [Return] foo bar zap
  • Using special keywords to return
    • Return From Keyword
    • Return From Keyword If

2.7.7 User keyword teardown

2.8 Resource and variable files

User keywords and variables in test case files and test suite initialization files can only be used in files where they are created

2.8.1 Resource files

  • Searching path
    • Absolute path
    • Otherwise
      • Relatively to the directory
      • PYTHONPATH
  • Resource file structure
    • Settings can only have Library, Resource, Variables
      Same keywords name from different resource file
  • Distinguish by file name without extension
    • myresources.Keyword
    • common.Keyword

2.8.2 Variable files

Taking variable files into use

  • Settings

    1
    2
    *** Settings ***
    Variables myvariables.py
  • Command lines

    ---variablefile myvariables.py

  • Creating variables in python

    1
    2
    3
    4
    VAR = "abcde"
    VAR2 = method()
    def method():
    return xxxxx

Selecting which variables to include

  • all variables not start with _ will be include as variables
    • even import math as _math def get_area()
  • Or we can specify __all__ = [‘VARNAME2’, ‘VARNAME2’]. Only variables in __all__ can be used

Getting variables from a special function

1
2
3
4
5
6
def get_variables(arg):
if arg == 'a':
variables = {"BAR": 7}
else:
variables = {"BAR": 77}
return variables

robot --variablefile ./varfile.py:a test.robot

Implementing variable file as Python or Java class: weird

Variable file as YAML: weird

2.9.1 Handling keywords with same names

  • Two kinds of keywords:
    1. Library keywords (from standard/external libraries)
    2. User keywords (user created/resourced)
  • Priority:
    • Highest - Keywords created in current file
    • Second - Resourced
    • Third - External library
    • Lowest - Standard library
  • Solution:
    • Specifying a keyword explicitly. e.g. Libraryname.Run
    • Specifying explicit priority using keyword. e.g. Set Library Search Order

2.9.2 Timeouts

We can set [Timeout] in Settings(default timeout for all test cases), Test Cases, Keywords

2.9.3 For loops

  • Simple for loop
  • Nested for loops
    • implemente by keyword
  • Using several loop variables

    1
    2
    3
    4
    5
    FOR    ${index}    ${english}    ${finnish}    IN
    ... 1 cat kissa
    ... 2 dog koira
    ... 3 horse hevonen
    FOR ${index} ${english} ${finnish} IN
  • For-in-range loop:

    for i in range(xx, xx):

  • For-in-enumerate loop

    for index, item in enumerate(my_list):

  • For-in-zip loop

    for i, j in zip(list1, list2):

  • Exiting for loop

    • Exit For Loop
      • Exit For Loo If
  • Continuing for loop
    • Continue For Loop
    • Continue For Loop If

Removing unnecessary keywords from outputs

Using command line option: –RemoveKeywords FOR

Repeating single keyword

Repeat Keyword 5 Some Keyword arg1 arg2

2.9.4 Conditional execution

  • Do not use if statement in Test Cases
  • Run Keyword: can set variable dynamically
  • If statement:

    1
    2
    Run Keyword If    '${status}' == 'good'    action
    Run Keyword Unless '${status}' == 'good' another action

or

Run Keyword If '${status}' == 'good' action ELSE another action

2.9.5 Parallel execution of keywords

  • Start Process
  • Read Process Output

3 Executing test cases

3.1 Basic usage

3.1.1 Starting test execution

3.1.2 Using command line options

  • Short and long options
    • robot --name test.robot
    • robot -N test.robot
  • Setting option values
    • robot --include tag
    • robot -i tag
    • robot --include=tag
    • robot -itag
  • Disabling options accepting no values
    • robot --dryrun
    • robot --nodryrun
  • Simple patterns
    • pattern: *, ?
    • robot --include f??
  • Tag patterns
    • AND, &
      • robot --include xx&yy
      • robot --include xxANDyy
    • OR
      • robot --include xxORyy
    • NOT
      • robot --include xxNOTyy
    • priority: AND > OR > NOT
  • ROBOT_OPTIONS and REBOT_OPTIONS environment variables
    • ROBOT_OPTIONS: default option for test execution
    • REBOT_OPTIONS: default option for result post-processing

3.1.3 Test results

  • Command line output
  • Generated output files
  • Return codes
    • Return code can be access by ‘echo $?’
    • --NoStatusRC: can set return code to be 0
  • Errors and warnings during execution

3.1.4 Argument files

Extract all options and arguments into an external file

  • --argumentfile xxxx

  • --argumentfile STDIN: we are able to read argumentfile from standard input, so we can

    • generate_argument.sh | robot --argumentfile STDIN

3.1.5 Getting help and version information

3.1.6 Creating start-up scripts

Modifying Java startup parameters

3.1.7 Debugging problems

  1. command line output
  2. log file
    • decrease loglevel, which shows in log.html
    • FAIL, WARN, INFO, DEBUG, TRACE
    • --loglevel DEBUG:INFO
      add Log, Log Variables in BuiltIn Keyword
  3. Robot Framework bug: set env ROBOT_INTERNAL_TRACES to anything
  4. Enable syslog
  5. Using the Python debugger (pdb): never mind
  6. Using Pycharm debugger. Edit configuration
    • Script Path: /Users/xxx/.pyenv/versions/3.7.2/lib/python3.7/site-packages/robot/run.py
    • Parameters: we can also add other parameters here like
      • e.g. –loglevel DEBUG /xxx/xxx/xxx.robot

3.2.1 Execution flow

Select test: --test, --suite, --include, --exclude

Suite setup:

  • if fail, all testcases, child suites won’t execute and will be marked failed as fail
  • Run before all tests and child suites

Suite teardown:

  • if fail, all testcase marked failed.
  • Run even suite setup fail
  • Run all keywords in it, even some keywords in it failed

  • Test setup, Test teardown

  • Keyword teardown, No Keyword setup

Execution order:

  • by filename
  • depth-first
  • if specify several tests, executed in the order they are given
  • add prefix to specify order
    • 01__my_suite.html -> My Suite
    • 02__another_suite.html -> Another Suite
  • randomize: –randomize

Passing execution:

  • Pass Execution/Pass Execution If
    • Pass execution of testcases directly
    • Better to set testcase non-critical

3.2.2 Continue on failure

  • Continue by keywords
    • Run Keyword And Ignore Error
    • Run Keyword And Expect Error
    • Run Keyword And Continue On Failure
  • Special failures
    • by creating exception
  • Execution continues on teardowns automatically
  • Execution continues on all data in templates

3.2.3 Stopping test execution gracefully

  • Pressing Ctrl-C
  • Using signals: kill INT or kill TERM
  • Using keywords: Fatal Error or fatal exceptions
  • Stopping when first test case fails or execution error
    • –exitonfailure: if any case fail, execution stop
    • –exitonerror: if any error, execution stop
  • Handling teardowns
    • –skipteardownonexit can skip teardown if execution stoped by above

3.3 Task execution

3.4 Post-processing outputs

  • Integral part of Robot Framework for handling output files
  • command: rebot

3.5 Configuring execution

3.5.1 Selecting files to parse

--extension robot:text

3.5.2 Selecting test cases

Select robot files to run

1
2
3
4
--test *test
--suite *test.xx
--include test*
--exclude test*

Re-executing failed test suites

Grab failed test and run them again

  • robot --rerunfailed output.xml tests
  • robot --rerunfailedsuites

When no tests match selection

Usually, we are given an error, but we can also run it by

  • –RunEmptySuite
  • –ProcessEmptySuite

3.5.3 Setting criticality

  • All testcase are critical by default
  • Failed noncritical test case will not affect overall status
    • –critical
    • –noncritical

3.5.4 Setting metadata

3.5.5 Configuring where to search libraries and other extensions

  • PYTHONPATH, JYTHONPATH and IRONPYTHONPATH
  • Using –pythonpath option
  • Configuring sys.path in program
  • Java classpath

3.5.6 Setting variables

3.5.7 Dry run

For validating syntax

3.5.8 Randomizing execution order

--randomize <what>[:<seed>]

3.5.9 Programmatic modification of test data

If the provided built-in features to modify test data before execution are not enough, Robot Framework 2.9 and newer makes it possible to do custom modifications programmatically

  • A python class extends SuiteVisitor
  • --prerebotmodifier xxx.py:arg1:arg2

3.5.10 Controlling console output

  • Console output type
  • Console width
  • Console colors

3.5.11 Setting listeners

For monitoring the test execution

  • –listener xxx
  • Listener interface

3.6 Created outputs

4 Extending Robot Framework

4.1 Creating test libraries

4.1.1 Introduction

4.1.2 Creating test library class or module

Test library names

When libraring a library, if classname == filename:
    Library    filename
else:
    Library    filename.classname

Test library scope

  • ROBOT_LIBRARY_SCOPE: TEST CASE; TEST SUITE; GLOBAL
  • ROBOT_LIBRARY_SCOPE = 'TEST SUITE'
  • Global and Test are for sharing state between tests

Specifying library version

  • ROBOT_LIBRARY_VERSION = '0.1'
  • or __version__ = 0.1
  • They will be written into the syslog

4.1.3 Creating static keywords

Create keyword in python file !

  • ignore methods begin with _

Keyword names

  • ignore space, underscore, case insensitive
  • custom keyword name by @keyword(‘Login As User’)

Keyword tags

  • @keyword(tags=['tag1', 'tag2'])

Argument types

  1. Manually: int(port)
  2. Decorator
    @keyword(types={'count': int, 'case_insensitive': bool})
  3. Implicit argument type
    def example_keyword(count=-1, case_insensitive=True)

If we specify as 2 and 3, argument type will be automatically converted.

Embedding arguments into keyword names

Awesome!!

1
2
@keyword('Add ${quantity:\d+} copies of ${item} to cart')
def add_copies_to_cart(quantity, item):

4.1.4 Communicating with Robot Framework

Reporting keyword status

  • Only AssertionError, Exception, RuntimeError shows exception messages
  • Self created Error should specify
    • ROBOT_SUPPRESS_NAME = True
  • Stopping/Continue test execution in exception class
    • ROBOT_EXIT_ON_FAILURE = TRUE
    • ROBOT_CONTINUE_ON_FAILURE = TRUE
  • Logging information into console

    1. ERROR and WARN will be written in console
      print('*WARN*', ...)
    2. stderr will be written in console
      • print('aaa', file=sys.stderr)
      • sys.__stdout__.write('Got arg %s\n' % arg)
    3. use robot logging API

      1
      2
      3
      from robot.api import logger
      logger.console('Got arg %s' % arg)
      logger.info('Got arg %s' % arg, also_console=True)
    4. use python logging API

      • import logging
      • logging.info('')

Communication when using threads

  • Supposed only main thread talk with robotframework
  • BackgroundLogger helps with not-main thread

4.1.5 Distributing test libraries

4.1.6 Dynamic library API

@keyword
get_keyword_names(self):
    return [name for name in dir(self) if hasattr(getattr(self, name), 'robot_name')]
run_keyword(self, name, args)
get_keyword_arguments 
get_keyword_documentation 
get_keyword_tags
get_keyword_types

4.1.7 Hybrid library API

Getting keyword names
Running keywords
Getting keyword arguments and documentation

4.1.8 Using Robot Framework’s internal modules

Available APIs: https://robot-framework.readthedocs.io/en/v3.1.1/
Using BuiltIn library

4.1.9 Extending existing test libraries

  • Modifying original source code: don’t do this
  • Using inheritance: cool
  • Using other libraries directly
  • Getting active library instance from Robot Framework

    1
    2
    3
    4
    5
    6
    7
    8
    from robot.libraries.BuiltIn import BuiltIn

    def title_should_start_with(expected):
    seleniumlib = BuiltIn().get_library_instance('SeleniumLibrary')
    title = seleniumlib.get_title()
    if not title.startswith(expected):
    raise AssertionError("Title '%s' did not start with '%s'"
    % (title, expected))
  • Libraries using dynamic or hybrid API

4.2. Remote library

4.2.1 Introduction

Allows distributed testing: have test library on different machine

4.2.2 Putting Remote library to use

  • Importing Remote library
    Library Remote http://10.0.0.2/example 1 minute WITH NAME Example3
  • Starting and stopping remote servers
    • start: by Process or SSH library
    • stop: remote server should supply Stop Remote Server keyword
      * ctrl-c on server
      * kill
      

4.2.3 Supported argument and return value types

XML-RPC protocol does not support all possible object types

4.2.4 Remote protocol

Executing remote keywords: it is just make a server

  1. Server side: RobotRemoteServer(Library(), host=xx, port=xx)
  2. Client side: Library Remote http://10.0.0.2/example 1 minute WITH NAME Example3
  3. So Robot framework is able to use it directly

4.3.1 Taking listeners into use

robot --listener listener.py:arg1:arg2 tests.robot

4.3.2 Listener interface versions

  • ROBOT_LISTENER_API_VERSION = 2: only gets information about the execution but cannot directly affect it
  • ROBOT_LISTENER_API_VERSION = 3: gets data and is able to alter execution

4.3.3 Listener interface methods

  • During the test execution different listener methods are called when test suites, test cases and keywords start and end
  • Listener version 2
    • start_suite, end_suite, start_test, end_test, start_keyword, end_keyword, log_message, message, output_file, log_file, report_file, debug_file
  • Listener version 3
    • library_import, resource_import, variables_import, xunit_file, close

4.3.4 Listeners logging

4.3.5 Listener examples

4.3.6 Test libraries as listeners

It is like combine library with listener

1
2
3
4
5
6
7
8
9
10
11
class PythonLibraryAsListenerItself(object):
ROBOT_LIBRARY_SCOPE = 'TEST SUITE'
ROBOT_LISTENER_API_VERSION = 2

def __init__(self):
self.ROBOT_LIBRARY_LISTENER = self

def _end_suite(self, name, attrs):
print 'Suite %s (%s) ending.' % (name, attrs['id'])

# actual library code here ...

Flask<1>--Decorator

Posted on 2019-01-13

Since Flask uses route() decorator to bind a function to a URL (Routing), this blog gives naive decorators and its corresponding code without decorator.

Level 1 (no parameters)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def wrapper(func):
def inner():
print("start")
func()
print("end")
return inner


def log():
print("logging")


log = wrapper(log)
log()

Corresponding decorator :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def wrapper(func):
def inner():
print("start")
func()
print("end")
return inner


@wrapper
def log():
print("logging")


log()

output:
start
logging
end

Level 2 (require parameter for log)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def wrapper(func):
def inner(file_name):
print("start")
func(file_name)
print("end")
return inner


def log(file_name):
print("logging " + file_name)


log = wrapper(log)
log('file')

Corresponding decorator :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def wrapper(func):
def inner(file_name):
print("start")
func(file_name)
print("end")
return inner


@wrapper
def log(file_name):
print("logging " + file_name)


log('file')

output:
start
logging file
end

Level 3 (Require parameter for decorator)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def wrapper(path_name):
def decorator(func):
def inner():
print("start logging in " + path_name)
func()
print("end")
return inner
return decorator


def log():
print("logging")


log = wrapper('path')(log)
log()

Corresponding decorator:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def wrapper(path_name):
def decorator(func):
def inner():
print("start logging in " + path_name)
func()
print("end")
return inner
return decorator


@wrapper("path")
def log():
print("logging")


log()

output:
start logging in path
logging
end

Level 4 (Require parameter for decorator&log)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def wrapper(path_name):
def decorator(func):
def inner(file_name):
print("start logging in " + path_name)
func(file_name)
print("end")
return inner
return decorator


def log(file_name):
print("logging " + file_name)


log = wrapper('path')(log)
log('file')

Corresponding decorator :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def wrapper(path_name):
def decorator(func):
def inner(file_name):
print("start logging in " + path_name)
func(file_name)
print("end")
return inner
return decorator


@wrapper('path')
def log(file_name):
print("logging " + file_name)


log('file')

output:
start logging in path
logging file
end

Vagrantfile<3>--Configure GUI inside of VM for Mac

Posted on 2018-12-31 | Edited on 2020-01-03

When using Vagrant for a project, we have two options.

  1. Using all development tools including IDE to edit code and compile in host, then run in VM.
      • better performance
      • synced_folder allows us to synchronize codes between VM and local.
      • hard to fix once mess up local development environment (like me !!!)
  2. Having another set of development tools in VM, developer writes code, compile and deploy in VM.
      • consistency: ensure the same development environment
      • lantency: GUI and Compiling. In SED, if I wanna use developer machine (like a high performance desktop), I have to ssh into server then vagrant ssh into VMs. We are now suffering high GUI latency when using IntelliJ in this situation (5 seconds for searching panel to show up). It is 2 X Forwarding, boss said it is an existing official bug.

In this blog, I will introduce these two methods.

IDE in host

This is achieved by a synced folder functionality of Vagrant. Introduced in Vagrantfile<2>–Vagrantfile
It synchronizes folder between VM and host.

Demo:

IDE in VM (Mac)

Relates keyword: DISPLAY, xhost, XForwarding, X Server, X Client

It is a little bit more complicated.
Basically, when running intelliJ, we should have a GUI window pop up. What we have to do now is to forward this window from VM to our host.

Some notations:

  • DISPLAY: an environment variable that indicates where to show this window.
    • Format: DISPLAY=IP:displaynumber.screennumber
    • e.g. DISPLAY=:0.0 show window in local
  • xhost: a list that is allowed to make connections to the X server
  • X Forwarding: Using X forwarding in an SSH session on your personal computer allows you to securely run graphical applications
  • X Server: e.g. host. It supplies screen for VM
  • X Client: e.g. VM. It uses the screen supplied by host.

Steps in theory

  1. Run a X Server in host (XQuartz for mac)
  2. Use X forwarding when ssh into VM
  3. Set proper DISPLAY in VM
  4. Run idea in VM

In Mac

  1. Install XQuartz, an Mac version of X Server.brew cask install xquartz
  2. Mac DISPLAY should already be set to DISPLAY=/private/tmp/com.apple.launchd.GxQDyjI1Mr/org.macosforge.xquartz:0
  3. vagrant ssh vm -- -X, -X relates to X forwarding.
  4. Run idea in VM

Common errors

  • Without X Server set.

    1
    2
    vagrant@ui:/synced_folder/idea-IC-183.4588.61/bin$ ./idea.sh
    Startup Error: Unable to detect graphics environment
  • Set DISPLAY in VM wihout X Server set.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    vagrant@ui:/synced_folder/idea-IC-183.4588.61/bin$ ./idea.sh

    Start Failed: Failed to initialize graphics environment

    java.awt.AWTError: Can't connect to X11 window server using ':0.0' as the value of the DISPLAY variable.
    at sun.awt.X11GraphicsEnvironment.initDisplay(Native Method)
    at sun.awt.X11GraphicsEnvironment.access$200(X11GraphicsEnvironment.java:65)
    at sun.awt.X11GraphicsEnvironment$1.run(X11GraphicsEnvironment.java:115)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.awt.X11GraphicsEnvironment.<clinit>(X11GraphicsEnvironment.java:74)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at java.awt.GraphicsEnvironment.createGE(GraphicsEnvironment.java:103)
    at java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(GraphicsEnvironment.java:82)
    at sun.awt.X11.XToolkit.<clinit>(XToolkit.java:128)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at java.awt.Toolkit$2.run(Toolkit.java:860)
    at java.awt.Toolkit$2.run(Toolkit.java:855)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.awt.Toolkit.getDefaultToolkit(Toolkit.java:854)
    at com.intellij.ui.AppUIUtil.updateFrameClass(AppUIUtil.java:161)
    at com.intellij.idea.StartupUtil.prepareAndStart(StartupUtil.java:94)
    at com.intellij.idea.MainImpl.start(MainImpl.java:20)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.ide.plugins.PluginManager.lambda$start$0(PluginManager.java:75)
    at java.lang.Thread.run(Thread.java:745)

reference

  • https://stackoverflow.com/questions/17625421/vagrant-for-a-java-project-should-you-compile-in-the-vm-or-on-the-host
  • https://blog.csdn.net/jlds123/article/details/6834287

Vagrantfile<2>--Vagrantfile

Posted on 2018-12-15

Introduction

Vagrantfile is a configuration file:

  • It describe and how to configure and provision these VMs.
  • The syntax of Vagrantfiles is Ruby
  • Use version control to share environment with team members.

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Vagrant.configure("2") do |config|
config.vm.define :ui do |ui|
ui.vm.provider "virtualbox" do |vb|
vb.memory = "1024"
vb.name = "ui"
vb.cpus = "4"
end
ui.vm.box = "centos/7"
ui.vm.hostname = "ui"
ui.vm.network "private_network", ip: "192.168.50.4"
end

config.vm.define :server do |server|
server.vm.provider "virtualbox" do |vb|
vb.memory = "1024"
vb.name = "ui"
vb.cpus = "4"
end
server.vm.box = "centos/7"
server.vm.hostname = "server"
server.vm.network "private_network", ip: "192.168.50.5"
end
end

box

1
server.vm.box = "centos/7"

It defines what box(system) for this VM. Find a box here public Vagrant box catalog

provider

1
2
3
4
5
ui.vm.provider "virtualbox" do |vb|
vb.memory = "1024"
vb.name = "ui"
vb.cpus = "4"
end

Used to modify settings which are specific to a certain provider

hostname

1
server.vm.hostname = "server"

Set hostname of this VM

network

How VM connect to the network. This one use private_network with a static IP. Options:

  1. private_network

    1
    server.vm.network "private_network", ip: "192.168.50.5"
  2. public_network

  3. forwarded_port

    1
    config.vm.network "forwarded_port", guest: 80, host: 8080

We can then open browser to localhost:8080 and browse the website, while all actual network data is being sent to the guest.

provision

  • Install and configure software automatically
  • It happens when vagrant up vagrant provision vagrant reload --provision
  1. file

    1
    config.vm.provision "file", source: "~/.gitconfig", destination: ".gitconfig"

    It upload this file/directory to new VM. So I don’t need to git config --global every time!!

  2. shell

    1
    config.vm.provision "shell", inline: "echo Hello, World"

    Run inline script

    1
    config.vm.provision "shell", path: "script.sh"

    Run external script

synced_folder

1
config.vm.synced_folder "src/", "/srv/website"
  • Didn’t use it in example because VirtualBox has its own share folder setting. This folders on your host machine can be synced to and from the guest machine
  • So useful!!!!!! Some personal setting can be sent to all VM. So I don’t need to worry about changing an alias at one VM, then have to edit all others

others

  • push

    • As of version 1.7, Vagrant is capable of deploying or “pushing” application code in the same directory as your Vagrantfile to a remote such as an FTP server.
  • plugin

    • we only have one called vagrant-libvirt

Vagrantfile<1>--Introduction&Commands

Posted on 2018-12-13 | Edited on 2018-12-15

Introduction

Vagrant is a tool for building and managing virtual machine environments.

Why do I use it?

To keep my local machine clean!!!     <(▰˘◡˘▰)>

Home Page

Installation

  1. Install Homebrew

    1
    /usr/bin/ruby -e "$(curl -fsSL https://	raw.githubusercontent.com/Homebrew/install/master/	install)"
  2. Install Virtualbox

    1
    brew cask install virtualbox
  3. Install Vagrant

    1
    brew cask install vagrant

Commands

Basic Commands

Command Usage
vagrant display all available subcommands
vagrant {subcommand} -h display usage for subcommands
vagrant box add add vagrant box
vagrant destroy destroys all resources that were created (doesn’t remove box installed during vagrant up)
vagrant halt shuts down the running machine Vagrant is managing
vagrant init init current directory by creating Vagrantfile
vagrant ssh ssh into vm
vagrant status display state of vms in this directory
vagrant up creates and configures guest machines according to your Vagrantfile

Common Commands

Command Usage
vagrant box list list all boxes
vagrant box remove remove a box
vagrant global-status show state of created machines for current user (vagrant status is only for current)
vagrant provision runs any configured provisioners against the running VM
vagrant reload vagrant halt; vagrant up. It can apply changes of Vagrantfile
vagrant resume resume machine that is vagrant suspend
vagrant snapshot similar as git stash, pop. Useful to try things and restore state
vagrant suspend suspend a VM instead of halt it. It no longer consume RAM.
vagrant validate validate Vagrantfile

Cloud&Share Commands

Command Usage
vagrant cloud manage things related to Vagrant Cloud
vagrant connect enabling access to shared environments by vagrant share
vagrant login authenticate with protected boxes in HashiCorp’s Vagrant Cloud or using vagrant share
vagrant share share vagrant environment with anyone else in world

Others

Command Usage
vagrant package package into a re-usable box
vagrant plugin manage plugins (we have a vagrant-libvirt plugin)
vagrant port displays the full list of guest ports mapped to the host machine ports
vagrant powershell this is only available for windows
vagrant rdp this is only available for windows
vagrant ssh-config This will output valid configuration for an SSH config file
vagrant version display version info
12
呆阿呆阿呆

呆阿呆阿呆

11 posts
5 tags
© 2020 呆阿呆阿呆
Powered by Hexo v3.8.0
|
Theme – NexT.Pisces v6.7.0