
今天遇到一个需求:做请求接口的封装,接口请求失败时,如无特殊处理则执行默认方法 defaultFunction (如弹窗提示),如有特殊处理则不执行默认方法。 如果用 callback 的写法很容易实现:
//封装方法 var ajax = function(option) { $.ajax({ url: option.url, fail: function() { if(!option.fail || typeof option.fail != 'function') { defaultFunction(); } } }) } //特殊处理,不执行默认 ajax({ url: 'a.url', fail: function() { console.log('error'); } }) //无特殊处理,执行默认 ajax({ url: 'a.url', }) 但是现在项目中的封装是基于 Promise 的,如下:
//封装方法 let p = (option) => { return new Promise((resolve, reject) => { $.ajax({ url: option.url, fail: () => { reject(); defaultFunction(); } }) }); } //调用 p({url: 'a.url'}).catch(() => { //... }) 求教:基于 Promise 是否可以实现类似上面「在调用处决定是否执行默认方法」的写法?
1 yokyj 2018-11-23 14:48:23 +08:00 //封装方法 let p = (option) => { return new Promise((resolve, reject) => { $.ajax({ url: option.url, fail: () => { reject( option.fail || defaultFunction); } }) }); } //调用 p({url: 'a.url'}).catch( cb => cb() ) |
2 xhyzidane OP @yokyj #1 感谢,你这个方法很好。 但是我已经采纳了另一种方案了:把是否执行默认行为作为一个标识在参数中传递。更适合我手上项目的实际需求。 可能是我的示例代码不好,其实现有封装的意思是:参数中并不传任何回调函数,而是 fail 时 reject,在 catch 中捕获。 |
3 SoloCompany 2018-11-23 22:45:18 +08:00 我们的选择是做了一个 promise 扩展框架 框架允许在 promise 上定义一个 uncaught 方法, 如果 promise 运行中的异常没有被捕获, 将会调用 uncaught 方法 比如 EPromise.reject(1) // 输出 Uncaught (in promise): 1 EPromise.reject(1).catch(noop) // 不输出任何内容 window.addEventListener(“ rejectionhandled ”) 可以有类似的作用, 但首先这个事件只有 chrome 支持, 其次只能是全局的, 不能对不同的 promise 实例使用不同的处理 |
4 hoyixi 2018-12-15 23:32:00 +08:00 $.ajax({...})本身就实现了 Promise 接口,可以直接 then: $.ajax({...}).then(...); $.ajax({...}).then(...).catch(...); |
5 xhyzidane OP @SoloCompany #3 你这个应该算是最符合场景的解决办法了,但是自己维护一套 promise 框架的代价太高了。我看了 bluebirdjs 里面有类似的实现,但好像也是全局的 |
6 SoloCompany 2018-12-16 23:49:58 +08:00 @xhyzidane 不是实现 promise 啊,只是对 promise 扩展包装一下, 两百行代码就够了 |
7 xhyzidane OP @SoloCompany #6 求教具体如何实现,我查到了一个实现方式 [https://github.com/rtsao/browser-unhandled-rejection]( https://github.com/rtsao/browser-unhandled-rejection) ,不知道是不是类似的 |
8 SoloCompany 2018-12-17 20:38:18 +08:00 @xhyzidane #7 大致的方案是使用包装和继承 对原始的 promise object 包装成一个新的 promise object, 并覆盖其 then 方法, 返回同样的经过包装的 promise object 在包装初始的时候, 就注册一个默认的 catch 链条, 处理默认的 catch 事件, 同时保留一个状态变量 如果被包装的 promise object 的 then 方法被调用, 就清理状态变量, 之前注册的默认 catch 方法不执行 |
9 SoloCompany 2018-12-17 20:45:33 +08:00 @xhyzidane #7 看了下 https://github.com/rtsao/browser-unhandled-rejection/blob/master/src/promise.js 思想上应该是差不多的,只不过我做了更多的扩展,所以代码会多一些 1. 兼容 ES3, 也就是说不使用 es6 的 class 扩展 2. 封装, 不暴露内部状态 (_hasDownstreams) 3. 扩展支持类似与 jquery 的 deferred 的用法支持多个参数 比如 EPromise.resolve(1,2).then(console.log) 能够输出 1 2 当然这种扩展有最大的局限性在于如果使用 async / await 则总是只能得到第一个结果 |
10 xhyzidane OP @SoloCompany #9 感谢大佬,学到了 |