一。js的异步
首先js语言的执行环境是单线程的即当一个任务完成时才能进行下一个任务 ,以此类推后面的任务都需要排队执行。 这样就会造成需要花费大量的时间执行完所有的任务,而且当一个任务中的代码出现错误或者死循环时那么下面的任务会无法执行。 所以Javascript在的处理模式分类异步和同步。 参考(https://juejin.im/post/5b605b035188251a90189c61)(https://es6.ruanyifeng.com/#docs/promise#Promise-all)
二。同步模式
后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的;
三。异步模式
"异步模式"则完全不同,每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。
四。常用的异步编程模式
回调函数 即f1,f2两个函数,f2要等待f1执行结果后执行,即 f1(f2)
事件驱动的方式 f1.on('done', f2); (JQ写法,f1完成时,trigger("done")则执行f2)
发布-订阅 模式
Promise对象实现
五。Promise的含义(https://es6.ruanyifeng.com/#docs/promise#Promise-all)
六。 基本用法
Promise对象是一个构造函数,用来生成Promise实例,Promise构造函数接收一个函数作为参数,与此同时该函数参数接收resolve和reject作为参数。 resolve将Promise的未成功状态转化成功的状态。将异步操作成果的结果传递过去。 reject将未失败转换为失败,将执行失败的结果传过去。当实例执行完成之后可调用then方法指定成功或失败的回调函数并执行后续的代码。
sun = ({a,b}) => {
return new Promise((resolve, reject) => {
/** 假设在这里执行了一些操作后得到其中的一个结果 **/
a >= b ? resolve("条件成立") : reject("条件不成立")
})
};
let a = sun({a:10,b:5}).then(data => {
console.log(data)
},error => {
console.log(error)
});
// 条件成立
let b = sun({a:1,b:10}).then(data => {
console.log(data)
},error => {
console.log(error)
});
// 条件不成立
七 Promise的特点
对象不受外界影响,初始状态为pending(等待中),结果的状态为resolve和reject之一
状态只能由pending变为另外两种的其中一种,且改变后不可逆也不可再度修改,
let promise = new Promise((resolve, reject) => {
reject('我失败了')
resolve('我成功了')
});
promise.then(data => {
console.log(data)
},error => {
console.log(error)
})
// 我失败了
let promise = new Promise((resolve, reject) => {
resolve('我成功了')
reject('我失败了')
});
promise.then(data => {
console.log(data)
},error => {
console.log(error)
})
// 我成功了
八。第一个axios的请求示例
假设我们这里有三个axios的请求。要求是要求时第三个请求要在第二个完成时触发。第二个要在第一个完成时触发。 这时传统的做法可能是。 只做示例
function request () {
axios.get('/user?ID=12345')
.then(function (response) {
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
})
.catch(function (error) {
console.log(error);
});
})
.catch(function (error) {
console.log(error);
});
}
或者
function request(callack) {
axios.get('/user?ID=12345')
.then(function (response) {
callack(response);
})
.catch(function (error) {
console.log(error);
});
}
request(data => {
if (data){
request(data1 => {
if (data1){
request(data3 => {
//
})
}
})
}
})
不难发现如果此时需要十个这样的请求呢 ? 二十个...... 甚至更多时显然不太现实。 此时尝试用Promise实现
methods:{
getData({url} = {}){
return new Promise((resolve, reject) => {
this.axios.get(url).then(res => {
if (res.data.status === 0){
resolve(JSON.parse(res.data.data))
}
}).catch(error => {
reject(error)
})
})
},
}
mounted: function () {
this.getData({url:api.jiaoxuehot + 1}).then(data => {
this.getData({url:api.newUpload + 1}).then(data => {
console.log(data)
},error => {
console.log(error)
})
console.log(data)
},error => {
console.log(error)
})
}
(20) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
(20) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
首先我们不难发现通过创建Promise对象可以成功的拿到了我们想要的数据。 但是貌似这个和我们初衷并不符。也没法解决多个请求所带来的不便。
九。Promise.all()
该方法用于将多个Promise实例重新包装成一个新的Promise实例。 尝试用该方法解决上面未解决的问题
methods:{
getData({url} = {}){
return new Promise((resolve, reject) => {
this.axios.get(url).then(res => {
if (res.data.status === 0){
resolve(JSON.parse(res.data.data))
}
}).catch(error => {
reject(error)
})
})
},
}
mounted: function () {
const a = this.getData({url:api.jiaoxuehot + 1});
const b = this.getData({url:api.wenhuahot + 1});
Promise.all(new Array(2).fill(a,b)).then(data => {
console.log(data)
},error => {
console.log(error)
})
}
[Array(20), Array(20)]
我们惊奇的发现这个新的Promise对象居然返回了两个数组。 且我们展开数据结构发现这正是我们想要的数据。到此为止我们上面的问题也就得到了解决
从上面的代码我们可以看出Promise.all()接受一个数组作为参数。并且a, b 都是Promise的实例。 如果其中一个不是就会调用Promise.resolve方法将参数转为实例。此外Promise.all()不仅仅只接受数组。 实际上可以具有Iterator接口的数据
Promise.all(最终的状态分为两种情况
1。a,b的状态都为fulfilled时。最终的结果才为fulfilled
2。a,b其中一个的状态为rejected时。 最终结果为rejected
十。Promise.race()
上面代码中,只要a,b之中有一个实例率先改变状态,p
的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p
的回调函数。
Promise.race()
方法的参数与Promise.all()
方法一样,如果不是 Promise 实例,就会先调用下面讲到的Promise.resolve()
方法,将参数转为 Promise 实例,再进一步处理。
methods:{
getData({url} = {}){
return new Promise((resolve, reject) => {
this.axios.get(url).then(res => {
if (res.data.status === 0){
resolve(JSON.parse(res.data.data))
}
}).catch(error => {
reject(error)
})
})
},
}
mounted: function () {
const a = this.getData({url:api.jiaoxuehot + 1});
const b = this.getData({url:api.wenhuahot + 1});
Promise.race(new Array(2).fill(a,b)).then(data => {
console.log(data)
},error => {
console.log(error)
})
}
(20) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
十一。Promise.prototype.then()
Promise 实例具有then
方法,也就是说,then
方法是定义在原型对象Promise.prototype
上的。它的作用是为 Promise 实例添加状态改变时的回调函数。前面说过,then
方法的第一个参数是resolved
状态的回调函数,第二个参数(可选)是rejected
状态的回调函数。
十二。Promise.prototype.catch()
Promise.prototype.catch()
方法是.then(null, rejection)
或.then(undefined, rejection)
的别名,用于指定发生错误时的回调函数。
new Promise((resolve, reject) => {
throw new Error("我抛出了错误")
}).catch(error => {
console.log(error)
})
Error: 我抛出了错误
at eval (home.vue?250d:285)
at new Promise (<anonymous>)
at new F (_export.js?90cd:36)
at a.mounted (home.vue?250d:284)
at Re (vue.min.js:6)
at $t (vue.min.js:6)
at Object.insert (vue.min.js:6)
at A (vue.min.js:6)
at a.__patch__ (vue.min.js:6)
at a.e._update (vue.min.js:6)