Javascript 中这种写法如何用 Promise 实现? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xhyzidane
V2EX    问与答

Javascript 中这种写法如何用 Promise 实现?

  •  
  •   xhyzidane 2018-11-22 23:55:52 +08:00 1999 次点击
    这是一个创建于 2539 天前的主题,其中的信息可能已经有所发展或是发生改变。

    今天遇到一个需求:做请求接口的封装,接口请求失败时,如无特殊处理则执行默认方法 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 是否可以实现类似上面「在调用处决定是否执行默认方法」的写法?

    10 条回复    2018-12-18 10:59:02 +08:00
    yokyj
        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() )
    xhyzidane
        2
    xhyzidane  
    OP
       2018-11-23 15:01:02 +08:00
    @yokyj #1 感谢,你这个方法很好。
    但是我已经采纳了另一种方案了:把是否执行默认行为作为一个标识在参数中传递。更适合我手上项目的实际需求。
    可能是我的示例代码不好,其实现有封装的意思是:参数中并不传任何回调函数,而是 fail 时 reject,在 catch 中捕获。
    SoloCompany
        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 实例使用不同的处理
    hoyixi
        4
    hoyixi  
       2018-12-15 23:32:00 +08:00
    $.ajax({...})本身就实现了 Promise 接口,可以直接 then:

    $.ajax({...}).then(...);

    $.ajax({...}).then(...).catch(...);
    xhyzidane
        5
    xhyzidane  
    OP
       2018-12-16 23:46:26 +08:00
    @SoloCompany #3 你这个应该算是最符合场景的解决办法了,但是自己维护一套 promise 框架的代价太高了。我看了 bluebirdjs 里面有类似的实现,但好像也是全局的
    SoloCompany
        6
    SoloCompany  
       2018-12-16 23:49:58 +08:00
    @xhyzidane 不是实现 promise 啊,只是对 promise 扩展包装一下, 两百行代码就够了
    xhyzidane
        7
    xhyzidane  
    OP
       2018-12-17 16:30:03 +08:00
    @SoloCompany #6 求教具体如何实现,我查到了一个实现方式 [https://github.com/rtsao/browser-unhandled-rejection]( https://github.com/rtsao/browser-unhandled-rejection) ,不知道是不是类似的
    SoloCompany
        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 方法不执行
    SoloCompany
        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 则总是只能得到第一个结果
    xhyzidane
        10
    xhyzidane  
    OP
       2018-12-18 10:59:02 +08:00
    @SoloCompany #9 感谢大佬,学到了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     987 人在   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 23ms UTC 22:41 PVG 06:41 LAX 14:41 JFK 17:41
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86