今天遇到一个需求:做请求接口的封装,接口请求失败时,如无特殊处理则执行默认方法 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 感谢大佬,学到了
|