看到精华里有篇文章叫做 如何让异步接口同时支持 callback 和 promise,少爷打算发表少爷在cnode的第一篇文章,无奈取名是个技术活,偏偏少爷又只有初中文凭,只好在原文标题上加了几个字,希望兄台莫怪👻
实现
我文采不好就不啰嗦了,直接上代码:
export const createPromiseCallback = () => {
let cb;
if (!global.Promise) {
cb = () => {};
cb.promise = {};
const throwPromiseNotDefined = () => {
throw new Error(
'Your Node runtime does support ES6 Promises. ' +
'Set "global.Promise" to your preferred implementation of promises.');
};
Object.defineProperty(cb.promise, 'then', { get: throwPromiseNotDefined });
Object.defineProperty(cb.promise, 'catch', { get: throwPromiseNotDefined });
return cb;
}
const promise = new global.Promise((resolve, reject) => {
cb = (err, data) => {
if (err) return reject(err);
return resolve(data);
};
});
cb.promise = promise;
return cb;
};
用法
function xxx(p1, p2, fn) {
fn = fn || createPromiseCallback();
// your code here...
return fn.promise;
}
栗子
// define
User.createPost = (id, post, fn) => {
fn = fn || createPromiseCallback();
User.findById(id, (err, user) => {
if (err) return fn(err);
if (!user) return fn(new Error('User is not found.'));
user.post.create(post, (err, post)=> {
if (err) return fn(err);
fn(null, post);
});
});
return fn.promise;
}
// use callback
User.createPost(userId, post, (err, instance) => {
// do something...
});
// use promise
User.createPost(userId, post).then((instance) =>{
// do something...
}).catch((err) => {
// handle error
});
把promise的逻辑单独拆出来,在需要兼容的函数里只要判断fn就行,是不是很优雅,少爷可不是标题党! 相信写过loopback的童鞋看着一定很熟悉,其实代码就出自loopback哦!
在dao层把promise的逻辑单独拆出来是必须的,而且未来有很多好处,尤其是和async结合的时候,升级代码也是非常简单的
简要解析:当fn
已定义,走回调流程;当fn
未定义,使用createPromiseCallback
来创建一个包含promise
属性的结果处理函数,实际上是把外部的回调形式通过包装委托给了内部属性的Promise
对象。createPromiseCallback
有一大半代码是用来做容错的,如果不存在global.Promise
,直接就给报个错,感觉省几行代码…
<small>如果学习的不对,题主指点一下下</small>
妙哉 妙哉
@DevinXian 大致就是这样,不过global.Promise是可以替换为别的Promise库,这样即便当前runtime原生不支持Promise也不会受到影响,而且可以把createPromiseCallback封装到单个文件里,每次用的时候只是对函数的两行代码做了修改,侵入性非常低,不仅省代码,可维护性也非常高
我觉得将callback和promise混用还是不太好。在这个例子中,createPost()有时候会返回promise,有时候又不返回,会让人迷惑 From Noder
@leizongmin 他的意思应该是两者都支持,随便用哪个的意思吧。我们团队API目前统一封装成promise型
@DevinXian 感觉callback和promise同时存在的应用场景应该是在sdk之类,不管你内部使用promise还是其他别的黑科技,但是呈现给用户使用的时候还是应该是callback