JS新特性(三)

all方法

  • Promise的all静态方法:
    • 1.all方法接收一个数组,
    • 2.如果数组中有多个Promise对象,只有都成功才会执行then方法,并且会按照添加的顺序, 将所有成功的结果重新打包到一个数组中返回给我们
    • 3.如果数组中不是Promise对象,那么会直接执行then方法
  • 示例
let arr = [
    "http://www.it666.com/files/system/block_picture_1555415767.png",
    "http://www.it666.com/files/system/block_picture_1555422597.jpg",
    "http://www.it666.com/files/system/block_picture_1555419713.jpg"
];
  • 示例1:无序加载图片, 每加载成功一张就添加一张
function loadImage(url) {
    return new Promise(function (resolve, reject) {
        let oImg = new Image();
        let time = Math.random() * 1000;
        // console.log(time);
        setTimeout(function () {
            oImg.src = url;
        }, time);
        // oImg.src = url;
        oImg.onload = function () {
            resolve(oImg);
        }
        oImg.onerror = function () {
            reject("图片加载失败了");
        }
    });
}

for(let i = 0; i < arr.length; i++){
    loadImage(arr[i]).then(function (oImg) {
        console.log(i);
        document.body.appendChild(oImg);
    }, function (msg) {
        console.log(msg);
    });
}

  • 示例2:无序加载图片,只有所有图片都加载成功才添加, 有一张图片失败都不添加
    • 应用场景: 批量加载, 要么一起成功, 要么一起失败
function loadImage(url) {
    return new Promise(function (resolve, reject) {
        let oImg = new Image();
        let time = Math.random() * 1000;
        // console.log(time);
        setTimeout(function () {
            oImg.src = url;
        }, time);
        // oImg.src = url;
        oImg.onload = function () {
            resolve(oImg);
        }
        oImg.onerror = function () {
            reject("图片加载失败了");
        }
    });
}

/*   有序的写法:
let p1 = new Promise(function (resolve, reject) {
    // resolve("111");
    reject("aaa");
});
let p2 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve("222");
    }, 5000);
});
let p3 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve("333");
    }, 3000);
});
Promise.all([p1, p2, p3]).then(function (result) {
    console.log("成功", result);
}, function (err) {
    console.log("失败", err);
});
*/

// 无序的写法:
Promise.all([loadImage(arr[0]), loadImage(arr[1]),loadImage(arr[2])])
.then(function (result) {
    // console.log(result);
    result.forEach(function (oImg) {
        document.body.appendChild(oImg);
    });
})
.catch(function (e) {
    console.log(e);
});

all方法实现

  • Promise的all静态方法特点
    • all方法会返回一个新的Promise对象
    • 会按照传入数组的顺序将所有Promise中成功返回的结果保存到一个新的数组返回
    • 数组中有一个Promise失败就会失败,只有所有成功才会成功
class MyPromise{
    static all(list){
        return new MyPromise(function (resolve, reject) {
            let arr = [];
            let count = 0;
            for(let i = 0; i < list.length; i++){
                let p = list[i];
                p.then(function (value) {
                    arr.push(value);
                    count++;
                    if(list.length === count){
                        resolve(arr);
                    }
                }).catch(function (e) {
                    reject(e);
                });
            }
        });
    }
}
// 测试:
let p1 = new MyPromise(function (resolve, reject) {
    // resolve("111");
    reject("aaa");
});
let p2 = new MyPromise(function (resolve, reject) {
    setTimeout(function () {
        resolve("222");
    }, 5000);
});
let p3 = new MyPromise(function (resolve, reject) {
    setTimeout(function () {
        resolve("333");
    }, 3000);
});

let pp = MyPromise.all([p1, p2, p3]);
console.log(pp);
pp.then(function (result) {
    console.log("成功", result);
}, function (err) {
    console.log("失败", err);
});

race方法

  • Promise的race静态方法:
    • 1.all方法接收一个数组
    • 2.如果数组中有多个Promise对象,谁先返回状态就听谁的, 后返回的会被抛弃
    • 3.如果数组中不是Promise对象,那么会直接执行then方法
let p1 = new Promise(function (resolve, reject) {
    // resolve("111");
    reject("aaa");
});
let p2 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve("222");
        // reject("bbb");
    }, 5000);
});
let p3 = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve("333");
        // reject("ccc");
    }, 3000);
});
Promise.race([p1, p2, p3]).then(function (value) {
    console.log("成功", value);
}).catch(function (e) {
    console.log("失败", e);   // 失败aaa,因为先执行的肯定是P1,所以p2/p3被抛弃
});

  • 应用场景: 接口调试, 超时处理
    • 示例:
let url = "http://www.it666.com/files/system/block_picture_1555415767.png";
function loadImage(url) {
    return new Promise(function (resolve, reject) {
        let oImg = new Image();
        setTimeout(function () {
            oImg.src = url;
        }, 5000);    // 改为3秒内,就会执行这个,输出变成成功
        oImg.onload = function () {
            resolve(oImg);
        }
        oImg.onerror = function () {
            reject("图片加载失败了");
        }
    });
}
function timeout() {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            reject("超时了");
        }, 3000);
    });
}
Promise.race([loadImage(url), timeout()]).then(function (value) {
    console.log("成功", value);
}).catch(function (e) {
    console.log("失败", e);   // 失败 超时了
});

race方法实现

  • Promise的race静态方法特点
    • 1.race方法会返回一个新的Promise对象
    • 2.谁先返回就听谁的
class MyPromise{
    static race(list){
        return new MyPromise(function (resolve, reject) {
            for(let p of list){
                p.then(function (value) {
                    resolve(value);
                }).catch(function (e) {
                    reject(e);
                });
            }
        })
    }
}
// 测试:
let p1 = new MyPromise(function (resolve, reject) {
    // resolve("111");
    reject("aaa");
});
let p2 = new MyPromise(function (resolve, reject) {
    setTimeout(function () {
        resolve("222");
        // reject("bbb");
    }, 5000);
});
let p3 = new MyPromise(function (resolve, reject) {
    setTimeout(function () {
        resolve("333");
        // reject("ccc");
    }, 3000);
});
MyPromise.race([p1, p2, p3]).then(function (value) {
    console.log("成功", value);
}).catch(function (e) {
    console.log("失败", e);
});

promise静态方法最终版

// 定义常量保存对象的状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class MyPromise{
    constructor(handle){
        // 0.初始化默认的状态
        this.status = PENDING;
        // 定义变量保存传入的参数
        this.value = undefined;
        this.reason = undefined;
        // 定义变量保存监听的函数
        // this.onResolvedCallback = null;
        // this.onRejectedCallback = null;
        this.onResolvedCallbacks = [];
        this.onRejectedCallbacks = [];
        // 1.判断是否传入了一个函数, 如果没有传入就抛出一个异常
        if(!this._isFunction(handle)){
            throw new Error("请传入一个函数");
        }
        // 2.给传入的函数传递形参(传递两个函数)
        handle(this._resolve.bind(this), this._reject.bind(this));

    }
    then(onResolved, onRejected){
        return new MyPromise((nextResolve, nextReject) => {
            // 1.判断有没有传入成功的回调
            if(this._isFunction(onResolved)){
                // 2.判断当前的状态是否是成功状态
                if(this.status === FULFILLED){
                    try {
                        // 拿到上一个promise成功回调执行的结果
                        let result = onResolved(this.value);
                        // console.log("result", result);
                        // 判断执行的结果是否是一个promise对象
                        if(result instanceof MyPromise){
                            result.then(nextResolve, nextReject);
                        }else{
                            // 将上一个promise成功回调执行的结果传递给下一个promise成功的回调
                            nextResolve(result);
                        }
                    }catch (e) {
                        nextReject(e);
                    }
                }
            }
            // 1.判断有没有传入失败的回调
            // if(this._isFunction(onRejected)){
            try {
                // 2.判断当前的状态是否是失败状态
                if(this.status === REJECTED){
                    let result = onRejected(this.reason);
                    if(result instanceof MyPromise){
                        result.then(nextResolve, nextReject);
                    }else if(result !== undefined){
                        nextResolve(result);
                    }else{
                        nextReject();
                    }
                }
            }catch (e) {
                nextReject(e);
            }
            // }
            // 2.判断当前的状态是否是默认状态
            if(this.status === PENDING){
                if(this._isFunction(onResolved)){
                    // this.onResolvedCallback = onResolved;
                    this.onResolvedCallbacks.push(() => {
                        try {
                            let result = onResolved(this.value);
                            if(result instanceof MyPromise){
                                result.then(nextResolve, nextReject);
                            }else{
                                nextResolve(result);
                            }
                        }catch (e) {
                            nextReject(e);
                        }
                    });
                }
                // if(this._isFunction(onRejected)){
                // this.onRejectedCallback = onRejected;
                this.onRejectedCallbacks.push(() => {
                    try {
                        let result = onRejected(this.reason);
                        if(result instanceof MyPromise){
                            result.then(nextResolve, nextReject);
                        }else if(result !== undefined){
                            nextResolve(result);
                        }else{
                            nextReject();
                        }
                    }catch (e) {
                        nextReject(e);
                    }
                });
                // }
            }
        });
    }
    catch(onRejected){
        return this.then(undefined, onRejected);
    }
    _resolve(value){
        // 这里是为了防止重复修改
        if(this.status === PENDING){
            this.status = FULFILLED;
            this.value = value;
            // this.onResolvedCallback(this.value);
            this.onResolvedCallbacks.forEach(fn => fn(this.value));
        }
    }
    _reject(reason){
        if(this.status === PENDING) {
            this.status = REJECTED;
            this.reason = reason;
            // this.onRejectedCallback(this.reason);
            this.onRejectedCallbacks.forEach(fn => fn(this.reason));
        }
    }
    _isFunction(fn){
        return typeof fn === "function";
    }
    static all(list){
        return new MyPromise(function (resolve, reject) {
            let arr = [];
            let count = 0;
            for(let i = 0; i < list.length; i++){
                let p = list[i];
                p.then(function (value) {
                    arr.push(value);
                    count++;
                    if(list.length === count){
                        resolve(arr);
                    }
                }).catch(function (e) {
                    reject(e);
                });
            }
        });
    }
    static race(list){
        return new MyPromise(function (resolve, reject) {
            for(let p of list){
                p.then(function (value) {
                    resolve(value);
                }).catch(function (e) {
                    reject(e);
                });
            }
        })
    }
}

用promise改造Ajax的封装

  • 封装代码:
<script>
function obj2str(data) {
    data = data || {};
    data.t = new Date().getTime();
    var res = [];
    for(var key in data){
        res.push(encodeURIComponent(key)+"="+encodeURIComponent(data[key]));
    }
    return res.join("&");
}
function ajax(option) {
    return new Promise(function (resolve, reject) {
        // 0.将对象转换为字符串
        var str = obj2str(option.data);
        // 1.创建一个异步对象
        var xmlhttp, timer;
        if (window.XMLHttpRequest){
            xmlhttp=new XMLHttpRequest();
        }else{
            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
        }
        // 2.设置请求方式和请求地址
        if(option.type.toLowerCase() === "get"){
            xmlhttp.open(option.type, option.url+"?"+str, true);
            // 3.发送请求
            xmlhttp.send();
        }else{
            xmlhttp.open(option.type, option.url,true);
            // 注意点: 以下代码必须放到open和send之间
            xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
            xmlhttp.send(str);
        }

        // 4.监听状态的变化
        xmlhttp.onreadystatechange = function (ev2) {
            if(xmlhttp.readyState === 4){
                clearInterval(timer);
                // 判断是否请求成功
                if(xmlhttp.status >= 200 && xmlhttp.status < 300 ||
                    xmlhttp.status === 304){
                    // 5.处理返回的结果
                    // console.log("接收到服务器返回的数据");
                    // option.success(xmlhttp);
                    resolve(xmlhttp);
                }else{
                    // console.log("没有接收到服务器返回的数据");
                    // option.error(xmlhttp);
                    reject(xmlhttp);
                }
            }
        }
        // 判断外界是否传入了超时时间
        if(option.timeout){
            timer = setInterval(function () {
                console.log("中断请求");
                xmlhttp.abort();
                clearInterval(timer);
            }, option.timeout);
        }
    });
}
</script>
  • 测试:
ajax({
    type:"post",
    url:"40.php",
    // 改成promise监听状态是否成功,就不用以下代码,改为then了
    // success: function (xhr) {
    //     let str = xhr.responseText;
    //     let json = JSON.parse(str);
    //     console.log(json);
    // },
    // error: function (xhr) {
    //     console.log(xhr.status);
    // }
}).then(function (xhr) {
    let str = xhr.responseText;
    let json = JSON.parse(str);
    console.log(json);
}).catch(function (xhr) {
    console.log(xhr.status);
});
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,776评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,527评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,361评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,430评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,511评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,544评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,561评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,315评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,763评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,070评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,235评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,911评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,554评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,173评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,424评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,106评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,103评论 2 352