好玩的.promise.all2

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Page Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
    <script>
        function http(url, method = 'post') {
            const xhr = new XMLHttpRequest();
            xhr.open(method, url);
            const promise = new Promise(function ($next, $done) {
                xhr.onreadystatechange = function () {
                    if (xhr.readyState === 4) {
                        if (xhr.status === 200) {
                            $next(xhr.response);
                        } else {
                            $done(xhr);
                        }
                    }
                };
                xhr.onabort = function () {
                    $done(null);
                };
                xhr.send();
            });
            promise.abort = function () {
                xhr.abort();
            };
            return promise;
        }
        function getRequest(index) {
            return [3, 6].includes(index)
                ? http('http://ifgm.cn/cors-error.php?index=' + index)
                : http('http://ifgm.cn/cors.php?index=' + index)
        }

        // 传入一个获取ajax的函数列表
        function listenerAjax(fns, onerror) {
            const COUNT = fns.length;
            let successData = [];
            let errored = false; // 多次,状态可重置
            let done = false; // 只有一次
            return new Promise(function ($next, $done) {
                function interceptThen(p, index) {
                    let _p = p.then(data => {
                        delete _p.abort;
                        successData[_p.index] = data;
                        if (successData.length === COUNT) {
                            $next(successData);
                        }
                        return data;
                    }, err => {
                        // 此时也会有其它请求失败,内部有定时器处理
                        if (!errored) {
                            errored = true;
                            // 第一次error,取消其它请求
                            // 同时删除当前请求,失败过了,就不重发了
                            delete _p.abort;
                            promises.forEach(item => {
                                if (item.abort) {
                                    item.abort();
                                    item.abort = true;
                                }
                            });
                            if (!onerror) {
                                if (!done) {
                                    $done(err);
                                    done = true;
                                }
                            } else {
                                // fix,abort循环期间,有的请求会完成(失败)
                                setTimeout(function () {
                                    Promise.resolve(onerror(err)).then(ignore => {
                                        if (!ignore) {
                                            // 发送已获取的数据
                                            $next(successData);
                                        } else {
                                            // 忽略错误
                                            successData[_p.index] = null;// null占位
                                            // 重置状态,递归
                                            errored = false;
                                            // 清除已完成
                                            {
                                                const _fns = [];
                                                const _promises = [];
                                                promises.forEach((item, index) => {
                                                    if (item.abort) {
                                                        const getAjax = fns[index];
                                                        _fns.push(getAjax);
                                                        promises.push(interceptThen(getAjax(), index));
                                                    }
                                                });
                                                fns = _fns;
                                                promises = _promises;
                                            }
                                            _p = null;
                                        }
                                    });
                                });
                            }
                        }
                        /**
                         * 有个问题就是,只能监听第一个错误请求,其它都被忽略,然后重发!
                         * 比如第一次 2个错误,只监听一个
                         * 第二次发送 9 个请求
                         * 
                         * 如果监听多个的话,需要显示的对abort之后返回的值判断。
                         */
                        // abort终止的请求,走这里,将promise改为resolve状态
                        return err; // Promise.reject(err)

                    });
                    _p.index = index;
                    _p.abort = p.abort;
                    return _p;
                }
                let promises = fns.map((getAjax, index) => interceptThen(getAjax(), index));
            });
        }
        listenerAjax(
            Array.from({ length: 10 }, (item, index) => getRequest.bind(null, index)),
            err => {
                return new Promise(($next, $done) => {
                    console.info('回车,忽略,继续\n空格,终止')
                    function mock(evt) {
                        // 回车,忽略,继续
                        if (evt.code === 'Enter') {
                            $next(true);
                        }
                        // 空格,终止
                        if (evt.code === 'Space') {
                            $next(false);
                        }
                    }
                    window.addEventListener('keypress', mock);
                });
            },
        )
            .then(data => {
                console.log(data);
            })
            .catch(err => {
                console.log(err);
            });
    </script>
</body>

</html>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值