Promise被我写嵌套了,请问如何优化?
发布于 9 年前 作者 dgnju 10510 次预览 最后一次回复是 9 年前 来自 问答
写了个了 redis 加锁的函数,写完发现 promise 嵌套了,感觉有点奇怪。
getLock: function (lockName, seconds) {
var self = this;
lockName = self.REDIS_LOCK_PREFIX + lockName;
var expireTimeInMs = Date.now() + seconds * 1000 + 1;
return self.setnx(lockName, expireTimeInMs).then(function (res) {
if (res === 1) {
return true;
} else {
return self.get(lockName).then(function (previousExpireInMs) {
// 过期死锁
if (previousExpireInMs < Date.now()) {
return self.getset(lockName,expireTimeInMs).then(function (getSetReturnExpireInMs) {
// 重新设置成功
if(previousExpireInMs===getSetReturnExpireInMs){
return true
}else{
return false
}
}).catch(function () {
return false;
})
}else{
return false
}
}).catch(function (err) {
return false;
})
}
}).catch(function (err) {
logger.error(``);
})
},
假设 setnx,get,getset 都是同步函数,那么我想实现的逻辑如下:
function getLock() {
var res = setnx(lockName, expireTimeInMs);
if (res === 1) {
return true;
} else {
var previousExpireInMs = get(lockName);
if (previousExpireInMs < Date.now()) {
var getSetReturnExpireInMs = getset(lockName, expireTimeInMs);
if (previousExpireInMs === getSetReturnExpireInMs) {
return true
} else {
return false
}
} else {
return false
}
}
}
我 promise 的写法感觉姿势不对啊,请同学帮忙指出,谢谢。
20 回复
首先
b 并不是1,你 return 有何意图 。
其次
else 可以去掉
你可以通过这段代码理解。
其他的没玩过。
你看下,这个是不是你想要的。
「Promise 对象的
then(onfulfilled)方法」返回「一个以onfulfilled函数的返回值进行 resolve 的 Promise 对象」。记住这点,你就可以把嵌套的 Promise 扁平化了。then…return…then…return
@MiYogurt getLock 要返回 Promise
@m31271n 假如3个嵌套的 Promise 每一个then 的返回都作为下一个的输入,3个都会执行的情况,很好拉平。到我这例子可能执行完某一个后面就不需要执行了,要能跳出来,困难在这
@alsotang 唐少,请问如果逻辑不需要一路then 到底,中途需要跳出来的情况怎么写呢? ( 如果某一环 reject 跳到 catch 里也觉得很怪)
这Promise写得还不如callback来得简单直接。
@leizongmin 主要是这个对象是提供API的,里面十几个函数都是返回 Promise, 想统一啊
@dgnju 我觉得可以像上面这样写: ES6 原生的 Promise 不提供 Promise.break 这种方法。但是可以使用 throw 来终止 Promise 链的继续执行。 最后使用 catch 捕获这些 throw 出的 true/false。
你需要一个 coroutine 库,比如 https://github.com/leizongmin/lei-coroutine
@m31271n 谢谢你的回复。throw 其实等于主动抛异常给 catch 块,这和 代码执行过程中真正的异常混到一块了,感觉也不太好。并且这里 Promise 整体上还是嵌套的。
@dgnju 确实异常混到一起了。刚刚,又处理了一下。
另外,这样,为什么是嵌套的呢?
@leizongmin 谢谢建议,只是上 coroutine 就需要上 generator 配合。 跟现有代码变化太大了。 这里确实不适合 Promise 优雅表达吗?我总感觉自己哪里没写好,想学习下如何处理
@m31271n 我是指 Promise 一层层嵌套起来了。 throw 和我直接 return true 和 false 差别不大。 原来的写法,在调用时 getLock(‘key’, 10).then( function (res) { // 这里也可以直接拿到 true 或 false })
@dgnju 用 yield
@dgnju 目前 Promise 对分支支持不太友好,用 reject 然后 .then(null,=>console.info()) 捕获怎么样? 用cacth没啥不好的啊,迭代器不也是用的异常实现的嘛?
用co改造后是不是更好理解呢
首先谢谢楼上各位的回复。 总结下: 如果需要提前跳出 promise 链,那么主要有2种方法:
如果可以引入 generator 的话,那么配合可以使用 co,或者 Promise.coroutine 等改善; 请参见楼上:@leizongmin @alsotang @chrislbb 等童鞋的回复
提供一种promise的写法, new Promise((res,rej)=>{ res(resObj);//or rej(rejObj); }) .then((data)=>{ return promise_task; }) .then(…) .catch(err=>{ }) promise_task写成这样的: fs.readFile(path,(err,doc)=>{ if(err)throw err; return doc; }) promise_task或者封装成promise化的函数 new Promise((res,rej)=>{ fs.readFile(path,(err,doc)=>{ if(err)rej(‘some error occur’); res(doc); }) }) }); 码字不易