在JavaScript的世界中,所有代码都是单线程执行的。由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现.
Promise是ES6中引入的一个异步编程解决方案,与传统的ES5方法相比它的结构更合理,功能更强大.
Promise
对象代表一个异步操作,有三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态.
语法:
var p = new Promise(function(resolve,reject){})
resolve 代表 决定(成功); reject 代表 失败
const p = new Promise(function(resolve,reject){
setTimeout(function(){
// resolve('我是成功的')
reject('这是失败的');
},2000)
});
.then(callback)的使用(成功时调用)
.catch(callback)的用法(失败时调用)
p.then(function(data){
console.log('resolved成功回调');
console.log('成功回调接受的值:',data);
}).catch(function(reason, data){
console.log('catch到rejected失败回调');
console.log('catch失败执行回调抛出失败原因:',reason);
});
效果和写在then的第二个参数里面一样。它将大于10的情况下的失败回调的原因输出
注意:resolve和reject的两种状态
resolve作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
我们用Promise的时候一般是包在一个函数中,在需要的时候去运行这个函数
let promiseFn =()=>{
console.log('点击方法被调用')
let p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('执行完成Promise');
resolve('成功的时候调用');
}, 2000);
});
return p
}
promiseFn().then(function(data){
console.log(11111)
}).catch(function(data){
console.log(2222)
})
使用promise检测ajax的请求状态,利用promise的成功状态函数,返回ajax请求到的数据
第一步,将ajax进行封装
const ajaxParam=param=>{
return new Promise(function(resolve,reject){
let xhr = new XMLHttpRequest();
xhr.open('get',param.url); // 默认是true,表示异步
xhr.onreadystatechange = function(){
if(xhr.readyState==4 ){
if(xhr.status==200){
resolve(xhr.responseText)
}else{
reject()
}
}
}
xhr.send();
});
}
第二步:使用then和catch获取结果,
ajaxPromise({type:'get', url:'http//:www.baidu.com',data:null})
.then(function(data){
}).catch(function(data){
});
所有的异步请求完成才执行的方法.
Promise.all在处理多个异步处理时非常有用,比如说一个页面上需要等两个或多个ajax的数据回来以后才正常显示,在此之前只显示loading图标。
let wake = (time) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`${time / 1000}秒后醒来`)
}, time)
})
}
let p1 = wake(3000);
let p2 = wake(2000);
Promise.all([p1, p2]).then((result) => {
console.log(result) // [ '3秒后醒来', '2秒后醒来' ]
}).catch((error) => {
console.log(error)
})
只有两次调用promise都执行完毕,才会执行all
Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
},1000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('failed')
}, 500)
})
Promise.race([p1, p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error) // 打开的是 'failed'
})
async/await
是一个 es7 的语法
这个语法是 回调地狱的终极解决方案
语法:
async function fn() {
const res = await promise对象
}
这个是一个特殊的函数方式
可以 await 一个 promise 对象
可以把异步代码写的看起来像同步代码
代码如下:
/*
pAjax({url: 'http://localhost:2305/user/test1'})
.then(data=>{
return get({url: 'http://localhost:2305/user/test2', params: {a: data}})
})
.then(data=>{
return pAjax({url: 'http://localhost:2305/user/test3', params: {b: data}})
})
.then(data=>{
console.log(data)
})
*/
// 这种方式比直接使用Promise更为优雅
async function request(){
// 可以把异步代码写的看起来像同步代码
let data1 = await get({url: 'http://localhost:2305/user/test1'})
console.log(data1)
let data2 = await get({url: 'http://localhost:2305/user/test2', params: {a: data1}})
console.log(data2)
let data3 = await pAjax({url: 'http://localhost:2305/user/test3', params: {b: data2}})
console.log(data3)
}
request()
封装的ajax请求.js源码
@params : 对象,第一个值是url 第二个值是传入的参数,以对象形式书写。
@return : 返回接受的数据
// get请求方式
function ajax_get(options){
let xhr = new XMLHttpRequest()
if(options.params){
let str = '?'
for(let key in options.params){
str += `${key}=${options.params[key]}`
str += '&'
}
str = str.slice(0, -1)
xhr.open('get', options.url+str)
}else{
xhr.open('get', options.url)
}
xhr.onreadystatechange = ()=>{
if(xhr.readyState == 4){
if(xhr.status == 200){
options.success && options.success(xhr.responseText)
}else{
options.error && options.error()
}
}
}
xhr.send()
}
// post请求方式
function ajax_post(options){
let xhr = new XMLHttpRequest()
xhr.open('post', options.url)
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
xhr.onreadystatechange = ()=>{
if(xhr.readyState == 4){
if(xhr.status == 200){
options.success && options.success(xhr.responseText)
}else{
options.error && options.error()
}
}
}
if(options.params){
let str = ''
for(let key in options.params){
str += `${key}=${options.params[key]}`
str += '&'
}
str = str.slice(0, -1)
xhr.send(str)
}else{
xhr.send()
}
}
// Promise版本ajax
function get(options){
return new Promise((resolve, reject)=>{
let xhr = new XMLHttpRequest()
if(options.params){
let str = '?'
for(let key in options.params){
str += `${key}=${options.params[key]}`
str += '&'
}
str = str.slice(0, -1)
xhr.open('get', options.url+str)
}else{
xhr.open('get', options.url)
}
xhr.onreadystatechange = ()=>{
if(xhr.readyState == 4){
if(xhr.status == 200){
resolve(xhr.responseText)
}else{
reject()
}
}
}
xhr.send()
})
}
function post(options){
return new Promise((resolve, reject)=>{
let xhr = new XMLHttpRequest()
xhr.open('post', options.url)
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
xhr.onreadystatechange = ()=>{
if(xhr.readyState == 4){
if(xhr.status == 200){
resolve(xhr.responseText)
}else{
reject()
}
}
}
if(options.params){
let str = ''
for(let key in options.params){
str += `${key}=${options.params[key]}`
str += '&'
}
str = str.slice(0, -1)
xhr.send(str)
}else{
xhr.send()
}
})
}