1.promise的由来
由于JavaScript是单线程的,在界面加载的时候从上至下依次载入。若此时界面中有一部分数据需要从后台获取而渲染,如果不采取异步措施,界面中未渲染的完的部分会等数据请求完成之后再渲染。这样对用户体验来说很不友好。这是一个方面,另外一方面,当我们执行完一个方法返回结果,另一个方法需要等第一个方法返回结果后才执行,这时候也需要异步。
最开始我们可以使用setTimeout来模拟异步操作:
setTimeout(function(){
console.log("console 1")
},1000)
function foo(){
console.log("console 2")
}
foo()
2.回调
function foo1(){
console.log("foo1")
}
function foo2(callback){
callback()
console.log("foo2")
}
foo2(foo1)
3.ajax 异步请求
我们常常使用ajax来异步请求数据。
$.ajax({
url:"",
type:"",
dataType:"",
data:"",
success:function(){},
error:function(){}
})
由于为异步请求,浏览器不会等请求结束之后再执行其他代码不用等待服务器处理请求,可以针对界面局部刷新处理。
当我们需要等上一个请求完成,再执行下一个请求的时候,我们可以这样写。
$.ajax({
url:"",
type:"",
dataType:"",
data:"",
success:function(){
if(success){
$.ajax({
url:"",
type:"",
dataType:"",
data:"",
success:function(){
......
},
error:function(){}
})
}
},
error:function(){}
})
这样代码整体看起来不太舒适,不过新版本的ajax已经有了更好的异步处理方式,它返回一个promise:
$.ajax({url:"",type:"",data:"",dataType:""}).then(function(){
$.ajax({url:"",type:"",data:"",dataType:""}).then(......)
})
看起来好像顺畅很多。
4.es6 promise
promise有两个函数参数:resolve和reject,分别代表成功和失败。
promise有三个状态:
– pengding (进行中)
– fulfilled (已成功)
– rejected (已拒绝)
当Promise状态为fulfilled时,调用 then 的 onfulfilled 方法,当Promise状态为rejected时,调用 then 的 onrejected 方法。
new Promise((resolve,reject)=>{
if(success){
resolve(data)
}else{
reject(error message)
}
}).then((data)=>{
console.log(data)
...
return data2
}).then((...)=>{
...
}).catch((error)=>{
console.log(error)
})
then方法接收的data参数是promise中resolve返回的值,后一个then方法中的参数为前一个then方法中的返回值。但是这样使用好像和ajax没多大区别,链式操作异步代码执行顺序。
不过promise有个all方法,可以并行执行函数,当函数之间没有相互等待关系的时候使用promise.all()会方便很多。
比如,现在有多个没有相互等待关系的ajax请求,我们可以这样写。
let request1 = $.ajax({url:"",type:"",dataType:"",data:""})
let request2 = $.ajax({url:"",type:"",dataType:"",data:""})
let request3 = $.ajax({url:"",type:"",dataType:"",data:""})
Promise.all([request1 ,request2 ,request3 ]).then((res)=>{
let [result1,result2,result3] = res
console.log(result1)
console.log(result2)
console.log(result3)
})
5.generator
generator函数:生成器函数,又称星号函数。也可以用来处理异步执行代码。
function* Foo(){
yield console.log("yield 1")
yield console.log("yield 2")
yield console.log("yield 3")
}
let foo = Foo()
foo.next() // yield 1
foo.next() // yield 2
foo.next() // yield 3
函数的主要特点是带有星号(位置左靠function或者右靠函数名),由yield控制执行顺序,看样子代码美化了不少。当我们需要等上一个请求结果返回再执行相关代码时,可以这样写。
function *someRequest(){
let result1 = yield $.ajax({url:"***",type:"post".dataType:"json",data:"**"})
yield $.ajax({url:"",type:"",dataType:"",data:result1})
}
let someRequest = someRequest()
someRequest.next().next()
相比于直接进行链式操作是不是更加浅显明了呢。但是生成器函数不支持箭头函数。
6.async await
async await 是最新的异步处理方案,也是我个人更青睐的处理异步操作的方法。它使用起来完全摆脱了链式操作,最大同步化了异步操作。它使用起来和生成器函数很像。
async function getData(){
let result = await $.ajax({url:"",type:"",dataType:"",data:""})
await $.ajax({url:"",type:"",dataType:"",data:result})
}
getData()
它需要在函数前加上async修饰词,在需要异步处理的函数前加上await关键词。调用的时候和调用普通函数一样。需要哪个请求执行在前哪个执行在后只需要按照顺序写就好了。看样子就像是同步请求一样。
相比于生成器函数,async await 更易于操控,而且支持箭头函数。
以上ajax请求替换成axios也是一样的处理。
注:以上代码为伪代码