Asynchronous solution — Promise

preface

Asynchronous programming module is becoming more and more important in front-end development. From the very beginning of XHR to the encapsulation of Ajax, attempts have been made to solve the problem of asynchronous programming. With the advent of the new ES6 standard, there are new solutions for handling asynchronous data flows. In traditional Ajax requests, when data between asynchronous requests was dependent on each other, inelegant layers of callbacks, commonly known as “callback hell,” could be a bit daunting. Promise was the way to move away from callback hell and write more elegant asynchronous code.

The downside of callback hell is the following:

  • Code bloat.
  • Poor readability.
  • The coupling degree is too high and the maintainability is poor.
  • Poor code reuse.
  • Bug prone.
  • Exceptions can only be handled in callbacks.

In practice, it turns out that promises aren’t perfect. Async/Await is one of the most revolutionary features added to JavaScript in recent years. Async/Await provides an alternative way to make asynchronous code look like synchronous code. Let’s take a look at these two options for handling asynchronous programming.

What is a Promise

Promise is a solution to asynchronous programming:

Syntactically, a Promise is an object that fetches messages for asynchronous operations;

In its original sense, it is a promise that will give you results over time.

This is a big pity. There are three states of promise: pending, successful, and rejected.

Once the state has changed, it will never change.

Once a Promise instance is created, it executes immediately.

Look at some familiar code:

// Promise is a constructor that has all, Reject,resolve,race methods on its own and then, catch, and so on on its prototype
let p = new Promise((resolve,reject) = >{
	// Do some asynchronous operations
	setTimeout((a)= >{
	/* let res = {ok:1, data:{name:" "}} */
		let res = {
			ok:0.error:new Error('wrong')}if(res.ok === 1){
			resolve(res.data);
		}else{
			reject(res.error.message)
		}

	}, 1000)})Copy the code

The state and value of the Promise

Promise objects can be in three states

  • Pending
  • This is a big pity.
  • Rejected(failed)

The state can only change from Pending to depressing or from Pending to Rejected. After the state changes, it will not change again and will always remain in this state.

The Promise value is the value passed to the callback function when the state changes

The arguments in the above example, resolve and reject, are functions that change the state of a Promise and the value of the incoming Promise

Resolve and reject

  • resolve: Changes the state of the Promise object fromPendingintoThis is a big pity.
  • reject: Changes the state of the Promise object fromPendingintoRejected(failed)
  • resolverejectCan be passed a value of any type as an argumentPromiseObject successfully(Fulfilled)And failure(Rejected)The value of the

Then method

p.then((data) = >{
	console.log(data);
    return data;
},(error)=>{
	console.log(error)
}).then(data= >{
    console.log(data);
})
Copy the code

The promise’s then method returns a Promise object, so the chain call can continue

We can continue to modify the above code, because the above code does not pass parameters

function timeout(ms) {
    return new Promise((resolve, reject) = > {
        setTimeout((a)= > {
            resolve('hello world')
        }, ms);
    })
}
timeout(1000).then((value) = > {
    console.log(value);
})
Copy the code

Rules for the THEN method

  • thenThe next input to the method requires the last output
  • If another promise is returned after a promise is executed, the execution result of the promise is passed to the next timethenIn the
  • ifthenReturns a normal value instead of a Promise object, which will be the result of the success of the next THEN
  • If the currentthenIf you fail, you go nextthenThe failure of the
  • If undefined is returned, success or failure will be followed by the next success
  • Catch is when an error is not handled
  • thenIf the method is not written to, the value is passed through to the next onethenIn the

Promise encapsulates XHR objects

const getJSON = function (url) {
    return new Promise((resolve, reject) = > {
        const xhr = new XMLHttpRequest();
        xhr.open('GET', url);
        xhr.onreadystatechange = handler;
        xhr.responseType = 'json';
        xhr.setRequestHeader('Accept'.'application/json');
        xhr.send();
        function handler() {
            console.log(this.readyState);
            if (this.readyState ! = =4) {
                return;
            }
            if (this.status === 200) {
                resolve(this.response);
            } else {
                reject(new Error(this.statusText));
            }
        }
    })
}
getJSON('https://free-api.heweather.net/s6/weather/now?location=beijing&key=4693ff5ea653469f8bb0c29638035976')
    .then((res) = > {
    console.log(res);

}, function (error) {
    console.error(error);

})

// Chain calls to the then method
getJSON('https://free-api.heweather.net/s6/weather/now?location=beijing&key=4693ff5ea653469f8bb0c29638035976')
    .then((res) = >{
    return res.HeWeather6;
}).then((HeWeather6) = >{
    console.log(HeWeather6);
})
Copy the code

Catch method

Catch (err=>{}) is equivalent to then(null,err=>{})

getJSON('https://free-api.heweather.net/s6/weather/now?location=beijing&key=4693ff5ea653469f8bb0c29638035976')
    .then((json) = > {
    console.log(json);
}).then(null,err=>{
    console.log(err);   
})
/ / equivalent to the
getJSON('https://free-api.heweather.net/s6/weather/now?location=beijing&key=4693ff5ea653469f8bb0c29638035976')
    .then((json) = > {
    console.log(json);
}).catch(err= >{
    console.log(err);   
})
Copy the code

resove()

The resolve() method will convert the existing object into a Promise object, and the state of this instance is fulfilled

let p = Promise.resolve('foo');
New Promise(resolve=>resolve('foo'));
p.then((val) = >{
    console.log(val);
})
Copy the code

reject()

The Reject () method returns a new Promise instance with the status Rejected

let p2 = Promise.reject(new Error('Wrong'));
// let p2 = new Promise((resolve,reject)=>reject(new Error(' Error ')));
p2.catch(err= > {
    console.log(err);
})
Copy the code

All () method

The all() method provides the ability to execute asynchronous operations in parallel and not execute callbacks until all asynchronous operations are complete

Imagine a page chat system where we need to obtain the user’s personal information and friend list from two different urls. These two tasks can be performed in parallel, using promise.all as shown below

let meInfoPro = new Promise( (resolve, reject) = > {
    setTimeout(resolve, 500.'P1');
});
let youInfoPro = new Promise( (resolve, reject) = > {
    setTimeout(resolve, 600.'P2');
});
// execute p1 and p2 at the same time, and execute then after they are both complete:
Promise.all([meInfoPro, youInfoPro]).then( (results) = > {
    console.log(results); // Get an Array: ['P1', 'P2']
});
Copy the code

Race () method

Sometimes, multiple asynchronous tasks are fault tolerant. For example, reading a user’s personal information from two urls at the same time only needs to get the result returned first. In this case, use promise.race () to implement:

let meInfoPro1 = new Promise( (resolve, reject) = > {
    setTimeout(resolve, 500.'P1');
});
let meInfoPro2 = new Promise( (resolve, reject) = > {
    setTimeout(resolve, 600.'P2');
});
Promise.race([meInfoPro1, meInfoPro2]).then((result) = > {
    console.log(result); // P1
});
Copy the code

Promise.all accepts an array of Promise objects, and after all completion, success will be executed uniformly;

Promise.race accepts an array of Promise objects, and as long as one completes, success is executed

For a more concrete example, deepen your understanding of the race() method

When we request an image resource, it will take too long to give feedback to the user

Use RACE to set a timeout for an asynchronous request and perform the corresponding operation after the timeout

function requestImg(imgSrc) {
   return new Promise((resolve, reject) = > {
        var img = new Image();
        img.onload = function () {
            resolve(img);
        }
        img.src = imgSrc;
    });
}
// The delay function is used to time the request
function timeout() {
    return new Promise((resolve, reject) = > {
        setTimeout((a)= > {
            reject('Image request timed out');
        }, 5000);
    });
}
Promise.race([requestImg('images/2.png'), timeout()]).then((data) = > {
    console.log(data);
}).catch((err) = > {
    console.log(err);
}); 
Copy the code

In addition to the above Api use of Promise, in fact, we need to understand more is the Promise of A+ specification is how to achieve, which is often asked in the interview, I hope the old iron come on