导读
当我们初始化一个 Promise 实例的时候,通常都会在回调函数里设置 Promise 实例状态的变更。
// a.js
const defer = new Promise(resolve => {
// 模拟异步
setTimeout(resolve, 3000);
});
export { defer };
// b.js
import { defer } from 'a';
defer.then();
这种用法是最常见的写法,可以把一些回调函数给 Promise 化。
从外部变更 Promise 实例状态
这里如果把 Promise 实例的回调入参给保存在全局作用域是不是可以呢?所以看一下这样的代码。
// a.js
let resolve;
const defer = new Promise(_resolve => {
resolve = _resolve;
});
// 模拟异步
setTimeout(resolve, 3000);
export { defer };
// b.js
import { defer } from 'a';
defer.then();
这两种写法的区别就是:resolve 被保存在外部了,对 Promise 实例的操作可以在外部执行了。
这样对 Promise 的初始化(new Promise()),Promise 实例状态变更操作(resolve()),对 Promise 的监听(defer.then()),这三个部分就可以分别写在不同的文件(或者说逻辑片段)中了。
// a.js
let resolve;
const defer = new Promise(_resolve => {
resolve = _resolve;
});
export { defer, resolve };
// b.js
import { defer } from 'a';
defer.then();
// c.js
import { resolve } from 'a';
setTimeout(resolve, 3000);
这里只是简单的例子,这个例子的明显缺点是这个 Promise 实例一旦被消费了就没用了。所以可以设计个工厂函数来优化它,这里就不写了。
使用场景
这种写法的使用场景是什么呢?这真的很难举例子,因为它的太不常用了。我唯一使用它的地方是用于关联 http 请求和 websocket 消息。
在 IM 消息系统中,用 http 发送一个 id 为 1 的消息,当服务端处理完毕后会通过 websocket 返回 id 为 1 的消息回执,然后基于回执来更新。
一般这里都会使用设计一个事件系统来处理,来看一下简单的伪代码
// send-msg.js
// 发送 http
const msg = {
id: 1,
message: '你好',
}
send(msg)
// websocket.js
// 监听 websocket
websocket.on('message', (msg) => {
update(msg);
})
这里有一个缺点,假如 msg 是一个数据元,那么对这个数据元的操作被分割到了两个文件(或者说逻辑片段)中了。理想中的写法可以如下:
send(msg)
.then(msg => {
update(msg);
});
那么使用上面 Promise 的方法是可以实现的,具体的情况还会有很多要处理,这里只写一个简单的伪代码例子说明一下。
// send-msg.js
import { defer } from 'a.js';
const msg = {
id: 1,
message: '你好',
}
function send(msg) {
return (
http(msg)
.then(() => {
return defer; // 这里会向外暴露 defer
})
)
}
send(msg)
.then(msg => {
update(msg);
})
// websocket.js
import { resolve } from 'a.js';
// 监听 websocket
websocket.on('message', (msg) => {
resolve(msg);
})
因为 defer(Promise 实例)和其 resolve 方法是关联的,所以这样写就可以把本来分散的逻辑整合起来,写起代码更加流畅。
这里只是提供一个思路,当遇到不好处理的场景时,多一条路走也许能豁然开朗。
罗小黑写写文字
如果喜欢文章 请留下一个赞~ 如果喜欢文章 分享给更多人~
在掘金中关注我
自由转载-非商用-非衍生-保持署名(创意共享3.0许可证) 转载时请保留原文链接 以保证可及时获取对文章的订正和修改