回调函数
在ajax出来之后异步开始变多了,我们就有了最常见的同步化需求例如回调函数。
$.ajax({
url:...,
type:...,
success:function(res){
$.ajax({
url:...,
type:...,
success:function(res){
$.ajax({
url:...,
type:...,
success:function(res){
}
})
}
})
}
})
下一次的请求需要依赖上一次请求的返回结果,所以需要层层嵌套,这个就叫做回调地狱。这种回调地狱在逻辑简单时还好,当逻辑复杂时,维护起来就非常麻烦,需要一层一层的剥开。
Promise
在ES6之后有了Promise对回调地狱进行了优化。使其从三角形的嵌套模式变为线性模式,使其更加直观便于维护。Promise有三种状态:pending(进行中)、resolved(成功)、rejected(失败)。
new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("省")
},1000)
}).then((res)=>{
console.log(res)
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("市")
},1000)
})
}).then((res)=>{
console.log(res)
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("区")
},1000)
})
})
其中Promise有两个主要用法:Promise.all和Promise.race。
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相当于“且”,当所有的任务完成之后再以数组的形式统一返回所有的resolve。
let wake = (time) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`${time / 1000}秒后醒来`)
}, time)
})
}
let p1 = wake(3000)
let p2 = wake(2000)
Promise.race([p1, p2]).then((result) => {
console.log(result) // '2秒后醒来'
}).catch((error) => {
console.log(error)
})
Promise.race相当于“或”,哪一个任务先完成,就返回这个resolve。
Generator
尽管Promise解决了回调地狱的问题,但是在Promise的线性模式中,任然存在回调。Generator是一个可以暂停和继续执行的函数,其实在ES6中的Generator不是专门用来解决Promise的回调问题的。但是其状态机模式可以很好的解决异步回调的问题。
Generator 基本语法包含两部分:函数名前要加一个星号;函数内部用 yield 关键字返回值。yield,表达式本身没有返回值,或者说总是返回undefined。next,方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。只有访问了next()才能执行下一步。
function * foo(x) {
var y = 2 * (yield (x + 1));
var z = yield (y / 3);
return (x + y + z);
}
var b = foo(5);
console.log(b.next()) // { value: 6, done: false }
console.log(b.next(12)) // { value: 8, done: false }
console.log(b.next(13)) // { value: 42, done: true }
其中done表示是否执行完成,在还未执行完yield之前,done为false,完成之后done为true。
Async/Await
Async其实就是Generator的语法糖,解决了Generator需要手动调用next的问题。其中async 对应的是 * ,await 对应的是 yield 。
async function asyyy(){
let data1 = await request('GET','http:.....')
return data2 = await request('POST','http:.....',{id: data1.id})
}
function request(type,url,params){
return new Promise({
$.ajax({
url: url,
type: type,
data: params,
success:function(res){
resolve(res)
},
error:function(err){
reject(err)
}
})
})
}
返回值是 Promise。async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then方法指定下一步的操作。 进一步说,async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。