手写Promise & ES6迭代器

手写实现Promise

Promise异步编程

  异步编程简介:无论在浏览器环境还是node环境都需要JavaScript的异步编程,如在浏览器环境中的定时器、事件、ajax等或是node环境中的文件读取、事件等。伴随着异步编程就有回调机制,异步编程免不了回调。

异步编程问题:产生回调地狱,难于维护和扩展。

try、catch只能捕捉同步代码中出现的异常。
同步并发的异步操作存在一定的问题。

解决方案: ES6 Promise可以解决回调地狱,以及同步并发的异步问题。
jQuery的Callbacks和Lodash的after都是解决回调问题的其他方法

Promise使用


//excutor function 同步执行

let promise = new Promise((resolve,reject)=>{

    //异步操作

    setTimeout(()=>{

        Math.random()*100 > 60 ? resolve("ok"): reject("fail");

    },1000);

});

//Promise内部状态,pending(等待),onFulFilled(成功),onReject(失败)

//注册回调,异步执行

//宏任务(setTimeout)    微任务

//微任务有优先执行权

//then 可以链式操作

//上一个then不抛出错误的话,下一个then会执行成功函数

//返回值作为下一个then注册函数的执行参数

//如果返回值为Promise对象,则下一个then的执行取决于该对象的执行函数

promise.then((val)=>{//微任务

    console.log(val);

    return new Promise((resolve,reject)=>{

        reject("newPromise:fail");

    });

},(reason)=>{

    console.log(reason);

    return "fail then1:param";

}).then((val)=>{

    console.log("ok then2:",val);

},(reason)=>{

    console.log("fail then2:",reason);

});

then 注册回调返回值
catch 异常捕获

let promise = new Promise((resolve,reject)=>{

    throw new Error("test error");

});

//失败函数捕获

promise.then(null,(reason)=>{

    console.log(reason);

});

//链式调用时如果有空then,则相当于不存在可忽视

//catch捕获

//catch后面可以继续链式调用

promise.then().catch((error)=>{

    console.log(error);

    }).then((val)=>{

        console.log(val,"after catch: ok");

    },(reason)=>{

        console.log(reason,"after ctach: fail");

    })

finally 最后处理函数
Promise.all 同步并发异步的结果

let oPro = new Promise(()=>{});

//Promise.all参数为数组,数组元素必须为Promise对象,其会将

//多个Promise实例包装成一个新的Promise实例。

//全部成功时数组内元素的返回值组成数组,只要有失败时返回最先被reject失败

//状态的值

Promise.all([oPro,oPro,oPro]).then((val)=>{

    console.log(val);//val为数组

});

Promise.race 谁先成功处理谁

let oPro = new Promise(()=>{});

//Promise.race([p1,p2,p3]);里面的哪个结果获得的快,就返回那个结果,

//不管结果本身成功或失败。谁的状态先发生改变就返回谁的状态

Promise.race([oPro,oPro,oPro]).then((val)=>{

    console.log(val);

},(reason)=>{

    console.log(reason);

});

Promise模拟实现

点击查看 [Promise规范][promise-standard]


//考虑兼容性,用ES5实现

function MyPromise(excutor) {

    this.status = "pending";

    this.resolveValue = null;

    this.rejectReason = null;

    this.resolveCallbackList = [];

    this.rejectCallbackList = [];

    try {

        excutor(this.resolve.bind(this), this.reject.bind(this));

    } catch (e) {

        this.reject(e);

    }

}

MyPromise.prototype = {

    resolve(val) {

        if (this.status === "pending") {

            this.status = "FulFilled";

            this.resolveValue = val;

            this.resolveCallbackList.forEach(function (cbFn) {

                cbFn();

            });

        }

    },

    reject(reason) {

        if (this.status === "pending") {

            this.status = "Rejected";

            this.rejectReason = reason;

            this.rejectCallbackList.forEach(function (cbFn) {

                cbFn();

            });

        }

    },

    then(onFulFilled, onRejected) {

        var self = this;

        self._dealNullThen(onFulFilled)._dealNullThen(onRejected);

        return new MyPromise(function (resolve, reject) {

            if (self.status === "FulFilled") {

                //模拟异步执行,此为宏任务,底层代码为微任务

                setTimeout(function () {

                    try {

                        var nextResolveValue = onFulFilled(self.resolveValue);

                        self._dealReturnValPromse(nextResolveValue, resolve, reject);

                    } catch (e) {

                        reject(e);

                    }

                }, 0);

            } else if (self.status === "Rejected") {

                setTimeout(function () {

                    try {

                        var nextRejectValue = onRejected(self.rejectReason);

                        self._dealReturnValPromse(nextRejectValue, resolve, reject, true);

                    } catch (e) {

                        reject(e);

                    }

                }, 0);

            } else if (self.status === "pending") {

                self.resolveCallbackList.push(function () {

                    setTimeout(function () {

                        try {

                            var nextResolveValue = onFulFilled(self.resolveValue);

                            self._dealReturnValPromse(nextResolveValue, resolve, reject);

                        } catch (e) {

                            reject(e);

                        }

                    }, 0);

                });

                self.rejectCallbackList.push(function () {

                    setTimeout(function () {

                        try {

                            var nextRejectValue = onRejected(self.rejectReason);

                            self._dealReturnValPromse(nextRejectValue, resolve, reject, true);

                        } catch (e) {

                            reject(e);

                        }

                    }, 0);

                });

            }

        });

    },

    _dealNullThen(fn) { //处理空then情况

        if (!fn) {

            fn = function (val) {

                return val;

            }

        }

        return this;

    },

    _dealReturnValPromse(returnVal, resolve, reject, isRejected) {

        if (returnVal instanceof MyPromise) {

            //若返回值为MyPromise对象,则后面的执行状态由该对象来决定

            returnVal.then(function (val) {

                resolve(val);

            }, function (reason) {

                reject(reason);

            });

        } else {

            //如果返回值不为MyPromise对象,则执行回调函数

            if (!isRejected) {

                resolve(returnVal);

            } else {

                reject(returnVal);

            }

        }

    },

};

MyPromise.race = function (promiseArr) {

    return new MyPromise(function (resolve, reject) {

        promiseArr.forEach(function (ele) {

            ele.then(resolve, reject);

        });

    });

};

//全部成功才执行成功回调,只要有一个失败就执行失败回调

MyPromise.all = function (promiseArr) {

    return new MyPromise(function (resolve, reject) {

        var returnValueArr = [],

            count = 0;

        for (var i = 0, len = promiseArr.length; i < len; i++) {

            (function (i) {

                promiseArr[i].then(function (val) {

                    returnValueArr[i] = val;

                    if (++count == len) {

                        resolve(returnValueArr);

                    }

                }, function (reason) {

                    reject(reason);

                });

            }(i));

        }

    });

};

ES6 Iterator

  迭代器目的:标准化迭代操作。

  迭代模式:提供一种方法可以顺序获得聚合对象中的各个元素,是一种最简单也是最常见的设计模式。它可以让用户透过特定的接口巡访集合中的每一个元素而不用了解底层的实现。

  迭代器简介:依照与迭代模式的思想而实现,分内部迭代器和外部迭代器。

    内部迭代器:本身是函数,该函数内部定义好迭代规则,完全接受整个迭代过程,外部只需要一次初始调用。

    Array.prototype.forEach、jQuery.each内部迭代器

    外部迭代器:本身是函数,执行返回迭代对象,迭代下一个元素必须显式调用,调用复杂度增加,但灵活性增强。

    function outerIterator(){}外部迭代器


//模拟写自己外部迭代器

function OuterIterator(o){

    let curIndex=0;

    let next=()=>{

        return {

            value:o[curIndex],

            done:o.length == ++curIndex,

        }

    }

    return {

        next,

    }

}

let arr=[1,2,3];

let oIt=outerIterator(arr);

oIt.next();

oIt.next();

oIt.next();

部署Iterator


let obj={

    0:"a",

    1:"b",

    2:"c",

    length:3,

    //要能迭代,必须部署Iterator,符合ES6

    [Symbol.iterator]:function (){

        let curIndex=0;

        let next = () => {

            return {

                value: this[curIndex],

                done: this.length == curIndex++,

            }

        };

        return{

            next,

        }

    },

}

console.log([...obj]);

Generator

Generator简介:生成器,本身为函数,执行后返回迭代对象,函数内部要配合yield使用,Generator函数分段执行,遇到yield即暂停。

特点:

  function和函数名之间需要带*

  函数体内yield表达式,产出不同的内部状态(值)


//示例 Generator产生迭代对象

function *test(){

    let val1= yield "a";

    console.log(val1);//val1的值为第二次next中传入的值

    yield "b";

    yield "c";

    return "d";

}

let oG=test();

oG.next();//{value:"a",done:false}

oG.next();//{value:"b",done:false}

oG.next();//{value:"c",done:false}

oG.next();//{value:"d",done:true}

改造前面的代码


let obj={

    0:"a",

    1:"b",

    2:"c",

    length:3,

    //要能迭代,必须部署Iterator,符合ES6

    [Symbol.iterator]:function (){

        let curIndex=0;

      while(curIndex != this.length){

          yield this[curIndex++];

      };

    },

}

console.log([...obj]);

Generator函数使用


function *read(path){

    let val1 = yield readFile(path);

    let val2 = yield readFile(val1);

    let val3 = yield readFile(val2);

    return val3;

}

let oG = read();

let {value, done} = oG.next();

value.then((val)=>{

    let {value, done} = oG.next();

    value.then((val)=>{

        let {value, done} = oG.next();

        value.then((val)=>{

            console.log(val);

        });

    });

});

//递归优化

function Co(oIterator){

    return new Promise((res,rej)=>{

        let next = (data)=>{

            let {value, done} = oIterator.next(data);

            if(done){

                res(value);

            }else{

                value.then((val)=>{

                    next(val);

                },rej);

            }

        };

        next();

    });

}

//使用

Co(read()).then((val)=>{

    console.log(val);

});

Promise化

let fs = require("fs");

let path="./data.txt";

let format="utf-8";

//原始函数

function readFile(){

    return new Promise((res,rej)=>{

        fs.readFile(path,format,(err,data)=>{

                if(err){

                    rej(err);

                }else{

                    res(data);

                }

            });

    });

}

//对函数进行promise化  (npm i bluebird)

function promisify(fn){

    return (...arg)=>{

        return new Promise((res,rej)=>{

            fn(...arg,(err,data)=>{

                if(err){

                    rej(err);

                }else{

                    res(data);

                }

            });

        });

    };

}

let readFilePromisify=promisify(fs.readFile);

readFilePromisify(path,format).then((val)=>{

    console.log(val);

});

//进一步对对象内异步方法进行promise化

function promisifyAll(){

    for(let key in obj){

        let fn=obj[key];

        if(typeof fn === "function"){

            obj[key + "Async"] = promisify(fn);

        }

    }

}

promisifyAll(fs);

fs.readFileAsync(path,format).then((val)=>{

    console.log(val);

});

async & await

async简介:async函数,是Generator语法糖,通过babel编译后可以看出它就是Generator+Promise+Co(递归)思想实现的,配合await使用。

目的:优雅的解决异步操作问题。


//解决回调地狱

//try catch

//同步并发的异步结果

async function read(path){

    try{

        let val1 = await readFile(path);

        let val2 = await readFile(val1);

        let val3 = await readFile(val2);

    }catch(e){

        console.log(e);//能够捕获异常

    }

    return val3;

}

read(path).then((val)=>{

    console.log(val);

});

//解决同步并发的异步问题

//Promise.all有局限性,一个异常其他也不能出结果

Promise.all([readFile(path1),readFile(path2),readFile(path3)])

.then((val)=>{

    console.log(val);

},(reason)=>{

    console.log(reason);

});

//使用async和await可以解决

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ES6迭代器(Iterator)是一种新的遍历机制,它有两个核心特点。首先,迭代器是一个接口,通过Symbol.iterator方法来创建迭代器,并通过迭代器的next()方法来获取数据。其次,迭代器是用于遍历数据结构的指针,类似于数据库的游标。例如,我们可以使用迭代器来遍历数组。比如,对于数组\[20,30,50,20,50\],我们可以通过arr\[Symbol.iterator\]()来创建一个迭代器,然后使用迭代器的next()方法来逐个获取数组中的元素。\[1\] 除了数组,具备Iterator接口的数据结构都可以进行解构赋值和扩展运算符(...运算符)操作。例如,字符串也具备Iterator接口,我们可以使用扩展运算符将字符串转换为字符数组。比如,对于字符串'hello',我们可以使用\[...str\]来将其转换为字符数组\['h', 'e', 'l', 'l', 'o'\]。这是因为字符串是具备Iterator接口的数据结构,我们可以自定义迭代器来遍历字符串中的字符。\[2\] 除了数组和字符串,还有其他可迭代的数据结构,比如类型数组(TypedArray)。我们可以使用for...of循环来遍历这些可迭代的数据结构。例如,对于数组\["zero", "one", "two"\],我们可以使用for...of循环来逐个输出数组中的元素。\[3\] #### 引用[.reference_title] - *1* [ES6 迭代器Iterator](https://blog.csdn.net/weixin_49342009/article/details/122665011)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [es6 迭代器iterator](https://blog.csdn.net/weixin_43443341/article/details/121417247)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [ES6迭代器 Iterator 详细介绍](https://blog.csdn.net/weixin_43856422/article/details/128290261)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值