Day15_promise解决回调地狱
1.promise()
promise中文意思是 “承诺”,这个就很有意思,我承诺***,就肯定不是马上就干,是承诺完之后就不知道什么时候干了,干完我再告诉你结果;
利用这种异步的执行机制,我们可以来规避函数的回调地狱。
- 回调地狱(函数作为参数层层嵌套)
ajax(url, function () {
ajax(url, function () {
ajax(url, function () {
ajax(url, function () {
ajax(url, function () {
ajax(url, function () {
ajax(url, function () {
})
})
})
})
})
})
})
- 为了避免回调函数的嵌套,找了第三方——状态机解决问题
promise三种状态:
- 等待状态 pending;
- 成功 resolved;
- 失败 rejected;
var p = new Promise(function (resolve, reject) {
var i = 5;
if (i > 3) {
// 只能带入一个参数
// resolve是正确时执行的
resolve(10,20);
} else {
// reject是错误时执行的
reject();
}
});
//如果没有调用then, promise执行了resolve不会报错, 而执行reject会报错
p.then(function (m, n) {
console.log(m, n);
}, function () {
console.log("bbb");
})
//10 undefined
- 当状态不是pending,将不会再次出发reject()或者resolve()
function fn() {
return new Promise(function (resolve, reject) {
for (var i = 0; i < 10; i++) {
if (i % 2 === 1) {
resolve();
} else {
reject();
}
}
})
}
fn().then(function () {
console.log("aaa");
}).catch(function () {
console.log("bbb");
})
// bbb
- promise 里面如果没有返回promise对象, 那么返回的为当前promise对象;
如果在内部创建并return了一个新的promise对象,则返回结果为新的promise对象;
let promise1 = new Promise(function(resolve, reject) {
setTimeout(function() {
console.log(1);
resolve();
}, Math.random() * 1000)
})
//下面的promise为promise1
promise1.then(function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log(2);
resolve();
}, Math.random() * 1000)
})
})
//下面的promise为新的promise2
.then(function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
console.log(3);
resolve();
}, Math.random() * 1000)
})
})
//下面的promise为新的promise3
.then(function() {
setTimeout(function() {
console.log(4);
}, Math.random() * 1000)
})
//输出结果:1 2 3 4
- reject后的东西,一定会进入then中的第二个回调。
var p1=new Promise((resolve,rej) => {
console.log('没有resolve')
//throw new Error('手动返回错误')
rej('失败了')
})
p1.then(data =>{
console.log('data::',data);
},err=> {
console.log('err::',err)
}).catch(
res => {
console.log('catch data::', res)
})
//输出结果:
//没有resolve
//err:: 失败了
- then中没有第二个回调的情况,则进入catch;如果有第二个回调,则不会进入catch。
var p1=new Promise((resolve,rej) => {
console.log('没有resolve')
//throw new Error('手动返回错误')
rej('失败了')
})
p1.then(data =>{
console.log('data::',data);
}).catch(
res => {
console.log('catch data::', res)
})
//没有resolve
//catch data:: 失败了
- 如果没有then, 也可以直接进入catch
- 不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。
var p1=new Promise((resolve,rej) => {
console.log('没有 resolve')
//throw new Error('手动返回错误')
rej('失败了');
})
p1.catch(
res => {
console.log('catch data::', res)
})
p1.finally(function() {
console.log("finally");
}
//没有resolve
//catch data:: 失败了
//finally
2.promise用法
- 图片链式加载
function loadImg(src) {
return new Promise(function (resolve, reject) {
var img = new Image();
img.src = src;
img.onload = function () {
resolve(img);
}
img.onerror = function () {
reject("加载地址错误:" + src);
}
})
}
loadImg("./img/36-.jpg").then(function (img) {
console.log(img);
return loadImg("./img/37.jpg");
}).then(function (img) {
console.log(img);
})
3.promise.all()
参数是一个可迭代对象,如
Array
或String
。返回一个
promise
实例,此实例在参数内所有的promise
都“完成(resolved)”或参数中不包含promise
时回调完成(resolve);如果参数中
promise
有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败promise
的结果。js是单线程的,而浏览器是多进程的。
- Promise.all预加载多张图片
function loadImg(src) {
return new Promise(function (resolve, reject) {
var img = new Image();
img.src = src;
img.onload = function () {
resolve(img);
}
img.onerror = function () {
reject("加载地址错误:" + src);
}
})
}
var arr = [];
for (let i = 2; i < 80; i++) {
arr.push(loadImg("./img/" + i + "-.jpg"));
}
console.log(arr); //注释1
Promise.all(arr).then(function (list) {
list.forEach(item => {
console.log(item.src);
})
})
上面注释1中,会打印有78项的数组,每一项都为状态为resolve的promise
注释1.jpg
- 重写promise.all()
class Promise1 {
static all(arr) {
return new Promise(function (resolve, reject) {
var i = -1;
var list = [];
loadImages();
function loadImages() {
i++;
if (i > arr.length - 1) {
resolve(list);
return;
}
arr[i].then(function (img) {
list.push(img);
loadImages()
})
}
})
}
}
- 同时发起两个请求,能够有效提高响应速度;
在处理多个异步处理时非常有用,比如说一个页面上需要等两个或多个ajax的数据回来以后才正常显示 。
Promise.all( [ajax("./server/get.php") , ajax("./server/get2.php")] )
.then(function(res){
console.log(res);
console.timeEnd("test");
})
- Promise.race
哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
类似于Promise.all() ,区别在于它有任意一个返回成功后,就算完成,但是进程不会立即停止;
常见使用场景:把异步操作和定时器放到一起,如果定时器先触发,认为超时,告知用户
Promise.race([ajax("./server/get.php"), ajax("./server/get2.php")])
.then(function(res) {
console.log(res);
console.timeEnd("test");
})
4. promise对比事件抛发时序
-
执行promise
promise是异步的,非即时性
console.log("111"); //promise是异步的,非即时性 Promise.resolve().then(function(){ console.log("aaa"); }) console.log("222"); //结果:111、222、aaa Promise.reject().catch(function(){ console.log("bbb"); })
-
事件抛发
抛发事件等同于调用事件的回调函数,是同步的
console.log("aaa"); document.addEventListener("aaa",function(){ console.log("ccc"); }) fn1(); console.log("bbb"); function fn1(){ var evt=new Event("aaa"); document.dispatchEvent(evt); // 抛发事件等同于调用事件的回调函数,是同步的 } //aaa ccc bbb