当逻辑需要回调函数时实现UI/logic分离

Achieving UI/logic separation when the logic requires callback functions

据我所知,在良好的实践中,UI 代码应该在需要时调用逻辑,但逻辑应该对 GUI 一无所知("loose coupling",参见示例 How can I separate the user interface from the business logic while still maintaining efficiency?).

我目前正在编写一个使用 chrome.serial api 的 chrome 网络应用程序。此 api 中的大多数函数都是非阻塞的,而是在它们的工作完成时调用回调函数。例如

chrome.serial.getDevices(callback)

搜索设备,然后使用找到的设备列表调用 callback

现在,在我的代码的逻辑部分调用 chrome.serial.getDevices 之后,其结果最终必须传回 UI 代码。

在这种情况下如何实现干净的 UI/logic 分离?我的 UI 是否需要在每次调用时使用我的逻辑代码注册回调函数?好像违背了上面的松耦合原则,感觉很快就变得很乱了。

您可以使用 Promises。在您的控制器代码中启动它们并将它们传递给视图。然后视图将调用其 .then() 方法并显示结果。

例如:

//controller.js
myAsyncTask = new Promise(resolve,reject=>{
   chrome.serial.getDevices(resolve)
})
view(myAsyncTask);

//view.js
function view(myAsyncTask){
   myAsyncTask.then(render);
}

如果您使用的是构建工具,例如 Webpack 或 Browserify,那么您可以让 "logic object" 扩展 Node 的 EventEmitter(还有其他可在浏览器中运行的实现,例如 https://github.com/Olical/EventEmitter,如果您不想将 Node APIs 与构建工具捆绑在一起)。

您的 "logic object",它是一个专门的 EventEmitter,操作 chrome async API,它联系串行设备,然后根据您的数据层规则处理结果,并且然后在它对 UI.

有一些有用的东西时发出自己的事件

UI 侦听既会侦听又会发出 "logic object" 上的事件,具体取决于发生的情况。奖励:这个事件发射器也可以被单独的 UI 对象使用,通过事件相互通信。

EventEmitter 是使这种分离感觉干净、简单且可扩展的关键。