同步和异步
同步和异步是一种消息通知机制
同步阻塞、同步非阻塞、(异步阻塞、异步非阻塞)(js中:前两种):小明去图书馆找书
- 小明:决定阻塞非阻塞,站在前台等 —— 阻塞,去干点其他事 —— 非阻塞
- 图书馆找书的管理员:决定异步同步,找到书有消息通知机制 —— 异步
- 如果图书馆找书的管理员没有消息通知机制,小明可以轮询
同步: 脑子一根筋,一件事做完再做下一件事:
A 调用B,B处理获得结果,才返回给A。A在这个过程中,一直等待B的处理结果,没有拿到结果之前,需要A(调用者)一直等待和确认调用结果是否返回拿到结果,然后继续往下执行。
异步: 一件事到了等待时间,我们继续做下一件事,不会原地等待上一件事执行完毕:
A调用B,无需等待B的结果,B通过状态,通知等来通知A或回调函数来处理。调用结果返回时,会以消息或回调的方式通知调用者。
js中我们会遇到哪些异步的情况?
- 定时器 setTimeout
- 动画帧 requestAnimationFrame
- 事件绑定
- 回调函数
- 数据请求 Ajax / 请求图片
- ...
event loop (wait...)
宏任务、微任务 (wait...)
回调地狱
function fn(cb){
setTimeout(()=>{
console.log("fn...")
cb && cb();
},100)
}
// 回调函数 cb
fn(function(){
console.log(2222);
});
回调嵌套层数过多,代码的结构就必然嵌套层级特别多, 造成可读性和维护性的直线下降
Promise 优化异步写法
resolve 调用 resolve 时:该异步执行完成,并且成功
reject 调用 reject 时:该异步执行完成,但是失败
栗子:
let p = new Promise((resolve, reject) => {
setTimeout(()=>{
reject(); // 找下面第一个回调(从0计数),如果有就调用,如果没有就报错
},3000);
}).then(()=>{
console.log("resolved"); // 成功
},()=>{
console.log("rejected"); // 失败
});
Promise:
三种状态 pending、resolved(fullfilled)成功、rejected
PromiseStatus Promise 中异步处理的当前状态
- pending 异步执行中
- resolved(fullfilled) 该 promise 执行完成,并且成功了
- rejected 该 promise 执行完成,但是出错了
then 两个参数 :onresolved ,onrejected链式操作(可选)
let p = new Promise((resolve,reject)=>{
// 异步处理
let img = new Image();
img.src = "...";
img.onload = function(){
resolve(img);
};
img.onerror = function(err){
reject(err);
};
});
// then 代表异步执行完了
p.then((img)=>{
document.body.appendChild(img);
},(err)=>{
console.log(err);
})
then 三种返还值
let p1 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("成功");
})
})
// 1.没有返还 -> 返还promise对象
let res = p1.then(res=>{
})
console.log(res);

let p1 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("成功");
})
})
// 2.返还值 -> 包装成promise对象返还
let res = p1.then(res=>{
return 111;
})
console.log(res);

let p1 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("成功");
})
})
// 3.返还promise对象 --> 原封不动返还promise对象;
let res = p1.then(res=>{
return new Promise(resolve=>{
resolve("返还的值");
})
})
console.log(res);

链式调用
p1.then(res=>{
return new Promise(resolve=>{
resolve(111)
});
}).then(res=>{
console.log(res); // 111 //promisevalue
}).then(res=>{
console.log(res); // undefined //promisevalue
}).catch(err=>{
console.log(err);
})

new Promise((resolve)=>{
console.log(1);
resolve();
}).then(()=>{
console.log(2);
}).then(()=>{
console.log(3);
}).then(()=>{
console.log(4);
});

new Promise((resolve)=>{
console.log(1);
resolve(111111);
}).then((res)=>{
console.log(2, res);
}).then((res)=>{
console.log(3, res);
}).then((res)=>{
console.log(4, res);
});

调用promise时候,返回一个新的Promise对象,调用then的时候也会返回新的Promise对象
new Promise((resolve)=>{
window.onload=function(){
resolve();
}
}).then(()=>{
return new Promise((resolve)=>{
box.style.width = "200px";
setTimeout(()=>{
resolve();
},1000)
})
}).then(()=>{
return new Promise((resolve)=>{
box.style.height = "200px";
setTimeout(()=>{
resolve();
},1000)
})
}).then(()=>{
console.log("动画执行结束");
});
then 的返回值:
then 方法会返回一个 新的 Promise
1. 默认情况下 then 会返回状态为 Resolved 的 Promise
2. 也可以直接在 then 的回调中返回一个 Promise 对象,该 Promise 会覆盖掉 then 默认返回的 Promise
出错的问题
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
// resolve();
reject("出错1");
},3000);
}).then(()=>{
console.log(1);
})
// 没有第二个参数,此时会报一个错误

<!--写上第二个参数后无报错,等于链式调用时,then里都需要写两个回调-->
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
// resolve();
reject("出错1");
},3000);
}).then(()=>{
console.log(1);
}, ()=>{
console.log(2);
})

<!--catch 方法:
用来捕获错误,走catch方法
catch 用来捕获错误
catch 捕获该链式调用中,之前的错误(只能捕获它之前的错误,后面的捕获不到)
catch 同 then 一样,都会返回一个 Promise 规则 和 then 一样
-->
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
//resolve();
reject("出错1"); //这里出错则下面俩then都不会执行了,直接跳到catch
},3000);
}).then(()=>{
console.log(1);
}).then(()=>{
console.log(2);
}).catch((err)=>{
console.log(err);
//此处的catch只能捕获上面的错误
// 捕获错误之后返回一个状态为resolve的Promise
}).then(()=>{
console.log(3);
}).then(()=>{
console.log(4);
return Promise.reject("错误2");
// 直接返回一个状态为 rejected 的 Promise
// 被下面的catch捕获
console.log(5);
}).catch((err)=>{
console.log(err);
})

// 接下来看看没出错时候的执行结果
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve(); //** 只有这里不一样哦 **
// reject("出错1");
},3000);
}).then(()=>{
console.log(1);
}).then(()=>{
console.log(2);
}).catch((err)=>{
console.log(err);
}).then(()=>{
console.log(3);
}).then(()=>{
console.log(4);
return Promise.reject("错误2");// 直接返回一个状态为 rejected 的 Promise
console.log(5);
}).catch((err)=>{
console.log(err);
})

静态方法,不需要new
Promise 下的方法:resolve、reject、all、race、finally
<!--
# Promise.reject
Promise.reject(reason) 返回一个状态为 Rejected 的 Promise 对象
参数:
reason 失败原因
# Promise.resolve
Promise.resolve(value) 返回一个状态为 resolved 的 Promise 对象
-->
let res = Promise.resolve("success");
console.log(res);

let res = Promise.reject("error");
console.log(res);

Promise.all
// Promise.all 所有promise对象都成功
// 图片很大,分成小块去请求,全部请求成功后执行
let p = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve();
console.log(1);
},1000);
});
let p2 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve();
console.log(2);
},2000);
});
let p3 = new Promise((resolve,reject)=>{
setTimeout(()=>{
reject();
console.log(3);
},2000);
});
Promise.all([p,p2,p3]).then(()=>{
console.log("成功"); // 全部成功
}).catch(()=>{
console.log("失败") // 有一个失败即失败
});
所有都成功输出结果
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111);
}, 2000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2222);
}, 1000)
})
// 等所有promise对象都成功输出
Promise.all([p1,p2]).then(res=>{
console.log(res);
})
2秒后的输出结果:

有一个失败,则拿不到结果
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("error");
}, 1000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2222);
}, 2000)
})
// 所有promise对象都成功
Promise.all([p1,p2]).then(res=>{
console.log(res);
})

Promise.race
拿到最先变化状态的那个
// Promise.race 但是其中有一项的状态发生改变新的实例的状态就会随着改变
Promise.race([p,p2,p3]).then(()=>{
console.log("成功");
}).catch(()=>{
console.log("失败")
});
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111);
// reject("error");
}, 1000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2222);
}, 2000)
})

finally
无论成功失败都要走到finally
成功
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111);
// reject("error");
}, 1000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2222);
}, 2000)
})
// finally :
p1.then(res=>{
console.log(res)
}).catch(err=>{
console.log(err);
}).finally(()=>{
console.log("执行完成");
});

失败
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve(111);
reject("error");
}, 1000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2222);
}, 2000)
})
// finally :
p1.then(res=>{
console.log(res)
}).catch(err=>{
console.log(err);
}).finally(()=>{
console.log("执行完成");
});
