• 1. Asynchronous programming
    • 1.1. Callback functions
    • 1.2 Publishing and Subscription
    • 1.3 Observer Mode

    • 1.4 Promise
  • Promise 2
    • 2.1 Promise.prototype.then()
    • 2.2 Promise.prototype.catch()
    • 2.3 Promise.all
    • 2.4 Promise.race
    • 2.5 Promise.resolve
    • 2.6 Promise.reject
    • 2.7 promiseSome extension libraries for the
    • 2.8 applicationsasync + await = generator + co
  • 3. Write A Promise A+
  • Reference documentation

1. Asynchronous programming

In the JavaScript world, all code is executed in a single line. Due to this “bug”, all web operations of JavaScript, browser events, must be executed asynchronously. Asynchronous execution can be done with:

  • The callback function
  • Release subscription
  • Observer model
  • promise

1.1. Callback functions
function call(id, callback){
  return function(){ callback(id+1); }}let fn = call(3, function(id){
  console.log(id);
})
fn();
Copy the code

Lodash inside the after function implementation method

function after(times, callback){
  return function(){// the number of times decreasesif(--times == 0){ callback(); }}}let fn = after(3, function(){
  console.log('After is called three times');
})
fn();
fn();
fn();
Copy the code

Then there is the common problem of reading data. With callback functions, we can only read one layer after another, and easily enter the horrible state of callback hell

let fs = require('fs');
let school = {}
fs.readFile('./age.txt'.'utf8'.function (err, data) {
    school['name'] = data;
    fs.readFile('./name.txt'.'utf8'.function (err, data) {
      school['age'] = data; //{ name:'cjw', age: '18'}}); });Copy the code
1.2 Publishing and Subscription

There is no dependency between publisher and subscriber. You may be a little unfamiliar with publish-subscribe, but you’ve used publish-subscribe as long as you’ve tied event functions to DOM nodes.

document.body.addEventListener('click'.function(){
  alert(2);
},false); document.body.click(); // simulate a user clickCopy the code

The implementation principle is to store the callback functions in an array ARR, and then execute the callback functions in the ARR when emit

let fs = require('fs');

letDep = {arr: [],// save the callback function on(callback){this.arr. Push (callback); },emit(){ this.arr.forEach(item=>{ item(); }}})letschool = {}; // Add a callback (subscribe) dep.on(function() {if(Object.keys(school).length === 2){ console.log(school); //{ name:'cjw', age: '18' }
    }
})
//
fs.readFile('./age.txt'.'utf8'.function(err, data){
    school['name'] = data; dep.emit(); }) fs.readfile () fs.readfile ()'./name.txt'.'utf8'.function(err, data){
    school['age'] = data; dep.emit(); / / release})Copy the code
1.3 Observer Mode

The observer pattern publishes and subscribes to the observer dependent

// class Observer{constructor(){
        this.arr = [];
        this.val = 1;
    }
    updateVal(val){
        this.val = val;
        this.notify();
    }
    notify(){ this.arr.forEach(s=>s.update()); } save(s){// Save an object this.arr.push(s); }} // Observed, observed has an updated method. class Subject{update(){
        console.log('update')}}let s = new Subject();
letobserver = new Observer(); observer.save(s); // Save an object observer.save(s); observer.updateVal(21); // When a value is updated, the observed also performs an update methodCopy the code
1.4 Promise

Promise has the following two characteristics: 1. The state of the object is not affected by the outside world. The Promise object represents an asynchronous operation with three states: Pending, fulfilled and Rejected. Only the result of an asynchronous operation can determine the current state, and no other operation can change the state. That’s where the name “Promise” comes from. Its English name means “Promise,” indicating that nothing else can change it. 2. Once the state changes, it will never change again. This result can be obtained at any time. There are only two possibilities for the state of the Promise object to change from pending to depressing and from pending to Rejected

let fs = require('fs');
function read(url){
    return new Promise((resolve, reject)=>{
        fs.readFile(url, 'utf8', (err, data)=>{
            if(err) reject(err); resolve(data); })})}let school = {};
read('./name.txt').then(data=>{
    school['name'] = data;
    return read('age.txt');
}).then(data=>{
    school['age'] = data; console.log(school); //{ name:'cjw', age: '18'}})Copy the code

Promise 2

2.1 Promise.prototype.then()

A Promise instance has then methods, that is, the THEN methods are defined in the prototype object

//let Promise = require('./promise.js');
let p = new Promise((resolve, reject)=>{
    setTimeout(function(){     
        reject('success');
    },100)
    reject('3'); }) p.then((value)=>{ console.log(value); }, (reason)=>{console.log(reason); })Copy the code

The basic concept

1. The new Promise requires passing an executor executor that immediately executes 2. The executor passes two arguments: resolve, which succeeds, can pass a value, which can be any value, reject, which fails, which can pass a value, which can be any value 3. You can only go from a pending state to a success or failure state. Each instance has a THEN method, which passes two parameters, one success and one failure 5. 6. Promise can use the same instance of THEN multiple times. If the state is pengding, the function needs to be stored until the state is determined and then the corresponding function will be executed successively (publish and subscribe). 7. The class becomes a failed state if an exception occurs during execution

The realization of the Promise. Prototype. Then ()

function Promise(executor){
    var self = this;
    self.status = 'pending'; // Switch from pending to resolved self.value = undefined; self.reason = undefined; self.onResolved = []; OnRejected = []; // Fixed message -> Resolvedfunction resolve(value){
        if(self.status === 'pending'){
            self.value = value;
            self.status = 'resolved';
            self.onResolved.forEach(fn=>fn());
        }
    }
     //pending -> rejected
    function reject(reason){
        if(self.status === 'pending'){
            self.reason = reason;
            self.status = 'rejected'; self.onRejected.forEach(fn=>fn()); } } try{ executor(resolve, reject); }catch(e){ reject(e); / /}}thenMethod implementation promise.prototype. then =function(onfulfilled, onrejected){
   let self = this;
   if(self.status === 'resolved'// This will be a big pity (self.value); }if(self.status === 'rejected'){// Check the status of the rejected, return reason onRejected (self.reason); }if(self.status === 'pending'){
      self.onResolved.push(function(){
          onfulfilled(self.value);
      })
      self.onRejected.push(function(){
        onfulfilled(self.reason);
      })
   }
}
module.exports = Promise;
Copy the code
2.2 Promise.prototype.catch()

The promise.prototype. catch method is an alias for. Then (null, Rejection) that specifies the callback when an error occurs.

let p = new Promise((resolve, reject)=>{
    resolve();
})
p.then(data=>{
    throw new Error();
}).then(null).catch(err=>{
    console.log('catch', err)
}).then(null, err=>{
    console.log('err', err);
})
Copy the code

Realize the principle of

Promise.prototype.catch = function(onrejected){
    return this.then(null, onrejected);
}
Copy the code
2.3 Promise.all

The promise.all method is used to wrap multiple Promise instances into a new Promise instance.

const p = Promise.all([p1, p2, p3]);
Copy the code

Realize the principle of

Promise.all = function (promises) {
    return new Promise((resolve, reject) => {
        let results = []; let i = 0;
        function processData(index, data) {
        results[index] = data; // let arr = []  arr[2] = 100
        if(++i === promises.length) { resolve(results); }}for (let i = 0; i < promises.length; i++) {
        letp = promises[i]; ProcessData (I, data); processData(I, data); }, reject); }})}Copy the code
2.4 Promise.race

The promise.race method also wraps multiple Promise instances into a new Promise instance.

const p = Promise.race([p1, p2, p3]);
Copy the code

In the above code, the state of P changes as long as one of the first instances of P1, P2, and P3 changes state. The return value of the first changed Promise instance is passed to p’s callback.

let Promise = require('./e2.promise');
let fs = require('mz/fs');

Promise.race([
    fs.readFile('./age.txt'.'utf8'),
    fs.readFile('./name.txt'.'utf8')
]).then(data=>{
    console.log(data);
})
Copy the code

Realize the principle of

Promise.race = function(promises){
    return new Promise((resolve, reject)=>{
        for(let i=0; i< promises.length; i++){
            letp = promises[i]; p.then(resolve, reject); }})}Copy the code
2.5 Promise.resolve

The Promise. Resolve method allows you to call an Resolved Promise object with no arguments.

const p = Promise.resolve();

p.then(function() {/ /... });Copy the code

Realize the principle of

Promise.resolve = function(value){
    returnnew Promise((resolve, reject)=>{ resolve(value); })}Copy the code
2.6 Promise.reject

The promise. reject method allows you to return a Promise object with the Rejected state without arguments.

const p = Promise.reject();

p.then(function() {/ /... });Copy the code

Realize the principle of

Promise.reject = function(reason){
    returnnew Promise((resolve, reject)=>{ reject(reason); })}Copy the code
2.7 promiseSome extension libraries for the

bluebird

mz

2.8 applicationsasync + await = generator + co

Generator A generator function that produces iterators * generator generally works with yield

function * read() {
    yield 1;
    yield 2;
    yield 3;
    return100}let it = read(a); console.dir(it.next()); console.dir(it.next()); console.dir(it.next()); console.dir(it.next()); // result: {value: 1,done: false }
{ value: 2, done: false }
{ value: 3, done: false }
{ value: 100, done: true }
Copy the code

promise + generator

let fs = require('mz/fs');
// let co = require('co');

function * read() {let age = yield fs.readFile('./age.txt'.'utf8');
    returnage; } / / cofunction co(it){
    return new Promise((resolve, reject)=>{
        function next(data){
            let { value, done } = it.next(data);
            if(!done){
                value.then(data=>{
                    next(data);
                }, reject)
            }else{
                resolve(value);
            }
        }
        next();
    })
}

co(read()).then(data=>{ console.log(data); //18 }, err=>{ console.log(err); })Copy the code

Async + await is es7 syntax

let fs = require('mz/fs'); // Async is a promise es7 // callback problem. Async is a try/catch problemfunction read() { 
    let age = await fs.readFile('name.txt'.'utf8')
    return age
}
read().then(data=>{ console.log(data); //cjw })Copy the code

3. Write A Promise A+

Promise A+ Specification portal

Test code for compliance with the A + specification in order for it to be testable

NPM install Promises -aplus-tests -g Promises -aplus-testsCopy the code
/* * @Author: caijw * @Date: 2018-10-01 15:04:43 * @Last Modified by: caijw * @Last Modified time: The 2018-10-08 22:41:06 * /function Promise(executor){
    var self = this;
    self.status = 'pending'; // Switch from pending to resolved self.value = undefined; self.reason = undefined; self.onResolved = []; OnRejected = []; // Fixed message -> Resolvedfunction resolve(value){
        if(self.status === 'pending'){
            self.value = value;
            self.status = 'resolved';
            self.onResolved.forEach(fn=>fn());
        }
    }
     //pending -> rejected
    function reject(reason){
        if(self.status === 'pending'){
            self.reason = reason;
            self.status = 'rejected'; self.onRejected.forEach(fn=>fn()); } } try{ executor(resolve, reject); }catch(e){ reject(e); }} // The recursive loop is used to determine whether it is a promise. If it is a promise, the recursive loop continues.function resolvePromise(promise2, x, resolve, reject){
    if(promise2 === x){
        return reject(new TypeError('Circular reference'));
    }

    let called;
    if(x! =null && (typeof x ==='object' || typeof x === 'function')){
        try{
            let then= x.then; // Suppose he is a promise,thenA method is a functionif(typeof then= = ='function'){
                then.call(x, (y)=>{
                    if(called) return;
                    called = true; ResolvePromise (promise2, y, resolve, reject) resolvePromise(promise2, y, resolve, reject); },(e)=>{if(called) return;
                    called = true; reject(e); })}else{// Resolve (x); } }catch(e){if(called) return;
            called = true; reject(e); }}else{ resolve(x); }} // To return an error catch does not write a successful callbackthenMethods Promise. Prototype. Catch =function(onrejected){
    returnthis.then(null, onrejected); // race () {// race () {// race () {// race () {// race () {// race (); Concurrency is initiated simultaneously, but the result is promise.race = with the fastest result returnedfunction(promises){
    return new Promise((resolve, reject)=>{
        for(let i=0; i< promises.length; i++){
            let p = promises[i];
            p.then(resolve, reject);
        }
    })
}


Promise.reject = function(reason){
    return new Promise((resolve, reject)=>{
        reject(reason);
    })
}

Promise.resolve = function(value){
    return new Promise((resolve, reject)=>{
        resolve(value);
    })
}

Promise.all = function (promises) {
    return new Promise((resolve, reject) => {
        let results = []; let i = 0;
        function processData(index, data) {
        results[index] = data; // let arr = []  arr[2] = 100
        if(++i === promises.length) { resolve(results); }}for (let i = 0; i < promises.length; i++) {
        letp = promises[i]; ProcessData (I, data); processData(I, data); }, reject); } // Promise.prototype.then =function(onfulfilled, onfulfilled){// Onfulfilled/onfulfilled is an optional parameter onfulfilled = typeof onfulfilled =='function' ? onfulfilled :  val=>val;
    onrejected = typeof onrejected === 'function' ? onrejected :err => {
        throw err;
    }
   let self = this;
   
   let promise2;
   promise2 = new Promise((resolve, reject)=>{
        if(self.status === 'resolved') {setTimeout(()=>{
                try{
                    letx = onfulfilled(self.value); resolvePromise(promise2, x, resolve, reject); }catch(e){ reject(e); }}}, 0)if(self.status === 'rejected') {setTimeout(()=>{
                try{
                    letx = onrejected(self.reason); resolvePromise(promise2, x, resolve, reject); }catch(e){ reject(e); }}}, 0)if(self.status === 'pending'){
            self.onResolved.push(function() {setTimeout(()=>{
                    try{
                        let x = onfulfilled(self.value);
                        resolvePromise(promise2, x, resolve, reject);
                    }catch(e){
                        reject(e);
                    }
                }, 0)
            })
            self.onRejected.push(function() {setTimeout(()=>{
                    try{
                        letx = onrejected(self.reason); resolvePromise(promise2, x, resolve, reject); }catch(e){ reject(e); }}, 0)})})returnpromise2; } // Syntax sugar simplifies problem nesting problem, deprecated promise.defer = promise.deferred =function() {let dfd = {};
    dfd.promise = new Promise((resolve, reject)=>{
        dfd.resolve = resolve;
        dfd.reject = reject;
    })
    return dfd;
}

module.exports = Promise;
Copy the code

Finally finished the promise, the friends saw, feel harvest, please give a thumbs up

Reference documentation

ECMAScript 6 Getting started Promise– Ruan Yifeng

Hey, you Promise

ES6 version Promise implementation, give you a different experience

Use Bluebird to develop asynchronous JavaScript programs