Handling concurrency gracefully
有一天,你想知道你家的小猫咪kakiki整天出去厮混的朋友有谁?
首先,你得知道你家猫咪的唯一标识id,然后再用这个id去数据库查它的朋友。
因此,你得发送两个请求,其中第一个请求结果是第二请求的参数。
相信,很多人都遇到过类似这样的情景吧!甚至可能需要发送五六个请求。怎么解决呢?
我们先来弄个假的数据库,用setTimeout来假装网络延迟(@ο@)
Make a fake db
class FakeDatabase{
constructor(){
this.purr = {
id: 1,
name: 'kakiki'
};
this.purrs = [this.purr, this.purr, this.purr];
}
getPurr(){
return new Promise((resolve, reject) => {
setTimeout(()=>resolve(this.purr), 233);
})
}
getPurrs(purrId){
return new Promise((resolve, reject) => {
setTimeout(()=>resolve(this.purrs.slice()), 233);
})
}
throwError(){
return new Promise((resolve, reject) => {
setTimeout(()=>reject(new Error('Internal error')), 233);
})
}
}
const db = new FakeDatabase();
let purr, purrs;
用回调是怎样写的呢?
In callback way
function callbackHell(){
db.getPurr().then((returnedPurr)=>{
purr = returnedPurr;
db.getPurrs(purr.id).then((returnedPurrs)=>{
purrs = returnedPurrs;
console.log("callbackHell ", {purr, purrs});
})
})
}
写完之后是不是觉得有点恶心,那我们用promise吧
(紫霞仙子,你还记得那个一万年期限的承诺吗/(ㄒoㄒ)/~~)
In promise chain way
function promiseChain(){
db.getPurr()
.then((returnedPurr)=>{
purr = returnedPurr;
return db.getPurrs(purr.id);
})
.then((returnedPurrs)=>{
purrs = returnedPurrs;
console.log("promiseChain ", {purr, purrs});
})
}
写完之后,觉得还是不够优雅。用async/await可以假装成是串行。(记得用babel来兼容老顽固😯)
In asyncAwait way
async function asyncAwait(){
try{
purr = await db.getPurr();
purrs = await db.getPurrs(purr.id);
console.log("asyncAwait ", {purr, purrs});
//循环遍历
const purrsPromises = purrs.map(purr => db.getPurrs(purr.id));
const morePurrs = await Promise.all(purrsPromises);
console.log('morePurrs ', morePurrs);
}catch(err){
//异常流
console.error(err);
}
}
现在终于知道kakiki的死党是谁了!!
而async/await又是怎么从promise、generator逐步演变过来的呢?
咱们下回分解。