手写实现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可以解决

手写Promise ES6迭代器相关推荐

  1. 方法 手写promise_JS探索-手写Promise

    无意间在知乎上刷到Monad这个概念,去了解了一下,前端的Promise就是一种Monad模式,所以试着学习一下手写一个Promise. 本文内容主要参考于 只会用?一起来手写一个合乎规范的Promi ...

  2. 手写 Promise

    手写 Promise 实现一个简易版 Promise 在完成符合 Promise/A+ 规范的代码之前,我们可以先来实现一个简易版 Promise,因为在面试中,如果你能实现出一个简易版的 Promi ...

  3. 手写Promise和all、race等方法,附上原理解析

    手写一个迷你版的Promise JavaScript 中的 Promise 诞生于 ES2015(ES6),是当下前端开发中特别流行的一种异步操作解决方案,简单实现一个迷你版本帮助深入理解 Promi ...

  4. vue 手写签名_手写Promise/Promise.all/Promise.race(手写系列一)

    背景 几个月没写文章了,愧对关注本专栏的小伙伴.最近有同学提议我出一个手写系列的文章对常见对前端工具.框架.设计模式做一个覆盖.同时有个要求:代码要尽量短小易懂,并且体现原理,让学习者学习过后能在未来 ...

  5. javascript --- 手写Promise、快排、冒泡、单例模式+观察者模式

    手写promise 一种异步的解决方案, 参考 Promise代码基本结构 function Promise(executor){this.state = 'pending';this.value = ...

  6. 一个下课的时间带你手写promise!

    要手写前先看看用法,用法就是我们的需求 //直接调用 let promise=new Promise((resolve,reject)=>{resolve('123') }) promise.t ...

  7. 面试必备--手写Promise.all与.race

    最近面试被问到了手写Promise .all 与 Promise.race,奈何没有自己实现过,只能阿巴阿巴 面完之后,冷静下来思考了该如何实现,并把他写了下来(在实现过程中确实收获不少,让我对这两个 ...

  8. 【Promise】自定义 - 手写Promise - Promise.all - Promise(executor)

    手写Promise 1. 整体结构框架 2. Promise(executor) 3. Promise.prototype.then 4. Promise.prototype.catch 5. Pro ...

  9. c0语言 测试用例,按照 Promise/A+ 手写Promise,通过promises-aplus-tests的全部872个测试用例...

    本文主要讲述如何根据 Promises/A+ 规范,一步步手写一个 Promise 的 polyfill,代码中会配上对应的规范解释. 1. 定义需要的常量和工具方法// 1. 定义表示promsie ...

最新文章

  1. Android 控件架构及View、ViewGroup的测量
  2. linux root目录install,Linux如何建立、删除、切换目录?
  3. 启明云端分享| SSD201 / SSD202D 在IP广播的应用
  4. Javascript的怪癖
  5. java删除list元素的几种方式
  6. Python 用pygame模块播放MP3
  7. CSS深入浅出(三)
  8. HDU 3861 The King’s Problem 强连通分量 最小路径覆盖
  9. NLP --- 文本分类(基于LDA的隐语意分析训练算法详解)
  10. 190704每日一句
  11. 推荐关于ElasticSearch的好文
  12. 阿里云:疫情期间全力保障教育平台“停课不停学”
  13. 一文带小白玩转NFC、门禁卡
  14. 首席科学家马丁•福勒(Martin Fowler)
  15. 比官方更简洁的Tensorflow入门教程
  16. PPT转Word文档及word图片批量居中
  17. hive:建库建表、表分区、内部表外部表、数据导入导出
  18. entity、bo、vo、po 如何理解和区分?
  19. tex常用函数 上下行对齐_tex常用函数 上下行对齐_【学术写作】如何优雅地(用TeX)写AI论文...
  20. 【Atcoder】Atcoder Beginner Contest 50

热门文章

  1. 【ROS全开源阿克曼转向智能网联无人驾驶车】开源教程(十三) 雷达跟随
  2. axios封装 —— 数据缓存、防止重复请求、动态加载
  3. 微信小程序——二维码推广海报
  4. 怎么才能搜索查找到大鱼号作者,为啥连大鱼号作者排行榜上的作者都找不到
  5. linux下载安装ngnix
  6. Power BI十大视觉效果,知多少?
  7. 排列组合算法的代码实现——附Python源码
  8. 本人在知乎平台的账号
  9. Java中使用枚举类和switch实现映射存储的类似策略模式实现定制化流程
  10. Typical memory leak (C++中典型的内存泄露)