大家都知道js是单线程的,所谓单线程就是两段js代码是不可能同时执行的,js有能力修改Dom,同一时间内不可能同时执行两段代码,两句都不行,这是为了避免DOM渲染的冲突。于是出现了SetTimeout,Ajax这些异步的函数,函数同步执行时遇到异步函数,异步函数被放到异步队列,代码自上往下执行,会根据事件轮询机制执行异步函数。
在工作中遇到这么一个问题,例如我要根据返回的数据动态生成一些元素,再对这些元素进行实例化,如果不使用回调函数的话这是会报错的,undefined,下图是用回调函数解决
思考一个问题,如果success里面的回调函数有多个,那么传参的时候要传入多个回调函数,再看一下下面的例子
传入多个回调函数控制台依次打印123,456,789,那么问题来了,我们是否可以用Promise改写一下呢?Promise就是为了解决异步而存在的
或者是
上面这里输出:
我们要做的就是在函数体里面new一个Promise对象,对象传入一个函数,再对这个函数传resolve,reject这两个方法,分别代表成功的方法和失败的方法,resolve,reject这两个方法再传参数,这样的话,后面在then的回调方法可以拿到,看下图
我觉得吧,promise其实是把原来传参的回调函数方式,抽出来写成了链式操作的形式,而then的第一个和第二个方法分别代表成功和失败的回调,这样代码易理解易维护。我们再举一些其他的例子,假如存在3个异步的请求,看下面
function runAsync(){
var p=new Promise(function(resolve,reject){
$.ajax({
type:"get",
url:"pdlist1.json",
async:true,
dataType:"json",
success:function(data){
resolve("我成功了1");
},
error:function(data){
reject("我出错了1")
}
});
})
return p
}
function runAsync1(){
var p=new Promise(function(resolve,reject){
$.ajax({
type:"get",
url:"pdlist1.json",
async:true,
dataType:"json",
success:function(data){
resolve("我成功了2");
},
error:function(data){
reject("我出错了2")
}
});
})
return p
}
function runAsync2(){
var p=new Promise(function(resolve,reject){
$.ajax({
type:"get",
url:"pdlist1.json",
async:true,
dataType:"json",
success:function(data){
resolve("我成功了3");
},
error:function(data){
reject("我出错了3")
}
});
})
return p
}
使用promise异步调用
runAsync().then(function(data){
console.log(data);
return runAsync1();
},function(data){
console.log(data);
return runAsync1();
}).then(function(data){
console.log(data);
return runAsync2();
},function(data){
console.log(data);
return runAsync2();
}).then(function(data){
console.log(data);
},function(data){
console.log(data);
})
如果3个异步方法都成功,会依次输出:我成功了1,我成功了2,我成功了3,我上面标明的红色返回一个方法,这个方法可以指明成功或者失败时做哪个的回调,再做个假设如果runAsync失败,会依次输出:我出错了1,我成功了2,我成功了3
关于catch的用法,catch用于捕获异常
假设上面的代码runAsync失败,其他成功,代码简写成这样
runAsync().then(function(data){
console.log(data);
return runAsync1();
}).then(function(data){
console.log(data);
return runAsync2();
}).then(function(data){
console.log(data);
}).catch(function(data){
console.log(data);
})
控制台输出:我出错了1,代码也不会往下执行了
假设上面的代码runAsync1失败,其他成功,则会输出:我成功了1,我出错了2,可以自己写代码慢慢体会
最后是两个关于Promise.all和Promise.race的用法
Promise.all是几个异步函数并行执行都完成时触发回调方法,有一个出错或者没完成都不会执行回调方法,以上面的3个异步Ajax请求为例:
Promise.all([runAsync(),runAsync1(),runAsync2()]).then(function(data){
console.log(data); // 3个成功输出数组【我成功了1","我成功了2","我成功了3"】
console.log("完成") //3个成功输出完成
}).catch(function(data){
console.log(data) //无输出
})
Promise.race是哪个异步函数最先完成为准就执行方法,race意为赛跑,以最快的为准
Promise.race([runAsync(),runAsync1(),runAsync2()]).then(function(data){
console.log(data); //输出我成功了1,runAsync()最先完成
console.log("完成")
}).catch(function(data){
console.log(data)
})
以上为学习Promise的总结