教你如何手写一个Promise
想要源码的可以看这里,里面也有一些其他的知识
想要手写一个promise,首先就要了解promise,想必大家都被过一些promise的面试题,知道一些promise的用法,主要考的就是一种异步编程的思想。
了解promise
我们先来看看直接输出一个promise对象会是什么,通过代码:
var p = new Promise((resolve,reject)=>{});
console.log(p);
可以看到输出结果Promise大致由它的状态PromiseState,它的值PromiseResult和它原型上面的方法组成。
promise对象有一个函数当作参数,函数里又分别有两个参数,分别是resolve和reject,当调用resolve()时就会运行prototype上的then()方法,当调用reject()时就会运行prototype上的catch()方法,这里的then,catch都是微任务,所谓微任务就是之宏任务运行完之后所运行的任务。就好比去银行办业务,你的要办的业务相当于宏任务,等你办完后银行工作人员会推荐与你业务相关的拓展业务,这个拓展业务就相当于微任务。
promise的状态有三种:等待(pending)、已完成(fulfilled)、已拒绝(rejected),并且状态只能由等待到完成或者等待到拒接。
开始写
了解promise之后我们就能把基本的架构写出来了。
function MyPromise(fn) {// promise 的状态this.PromiseState = "pendding";// promise 的值this.PromiseResult = undefined;var resolve = (value) => {};var reject = (errValue) => {};if (fn) {fn(resolve, reject);}}
这里定义初始状态pedding,和初始值undefined,resolve,reject两个方法。
完成then
首先先完成then的成功运作,如何能让如下代码成功输出:
var p = new MyPromise((resolve, reject) => {resolve("resolve");});p.then((res) => {console.log(res);console.log("then执行");});
这里就需要完善resolve和原型对象上写then方法:
// 定义一个函数对象,用来注册then中的callback
this.thenCallback = undefined;
var resolve = (value) => {// 更改promise的状态和值if (this.PromiseState == "pendding") {this.PromiseState = "fulfilled";this.PromiseResult = value;if (value instanceof MyPromise) {value.then((res) => {if (this.thenCallback) {this.thenCallback(res);}});} else {setTimeout(() => {if (this.thenCallback) {this.thenCallback(value);}});}}};
MyPromise.prototype.then = function (callback) {return new MyPromise((resolve, reject) => {this.thenCallback = (value) => {// 在使用链式调用的时候,可能第一个调用的不是catch// 使用我们在做检测时会借助then来将catch的信息向下传递// 所以我们检测到触发thenCallback的对象是rejected时// 我们就继续调用下一个rejectif (this.promiseState == "rejected") {reject(value);} else {var res = callback(value);// 这里防止中间返回是一个promise对象它会继续找then,直接让他调用rejectif (res instanceof MyPromise && res.promiseState == "rejected") {res.catch((errValue) => {reject(errValue);});} else {// 这里定义给变量res在调用resolve是为解决.then()的链式调用resolve(res);}}};});};
定义一个函数对象,用来注册then中的callback,首先判断promise的状态,如果是pendding则转换成fulfilled,并将参数值赋值给promiseResult;
if (value instanceof MyPromise)是为了判断value是否是一个Promise对象,如果是就使用自己定义的then,因为then时异步执行的,所以使用setTimeout
当then链式调用时,如then().then(),第一个then中如果有返回值,那么这个返回值将会作为第二个then中的参数,所以需要每个then返回一个新的promise对象return new MyPromise()。
这里再封装一个MyPromise.resolve的快捷调用:
MyPromise.resolve = (value) => {return new MyPromise((resolve, reject) => {resolve(value);});};
完成catch
catch与then大致相同,只需要稍作修改。这里完善reject方法和原型上的catch:
this.catchCallback = undefined;
var reject = (errValue) => {if (this.promiseState == "pendding") {this.promiseState = "rejected";this.promiseResult = errValue;// 判断写没写catch()setTimeout(() => {if (this.catchCallback) {this.catchCallback(errValue);} else if (this.thenCallback) {this.thenCallback(errValue);} else {throw "catch is not defined!!!!";}});}};
首先判断promise的状态,如果是pendding则转换成frejected,并将参数值赋值给promiseResult;
这里有可能再调用catch前还调用了then方法,所以使用else if判断是不是,时就运行this.thenCallback(errValue);,因为之前在then会判断promise状态是不是rejected,如果是就重新调用reject()方法。
MyPromise.prototype.catch = function (callback) {return new MyPromise((resolve, reject) => {this.catchCallback = (errValue) => {var res = callback(errValue);reject(errValue);};});};
这里也继续封装一个MyPromise.reject的快捷调用:
MyPromise.reject = (errValue) => {return new MyPromise((resolve, reject) => {reject(errValue);});};
promise中的api,all和race
all和race传入的参数都是一个数组,all将会等最长时间结束后按数组的顺序,而race则会执行最早的那一个。
MyPromise.all = (promiseArr) => {let resArr = [];return new MyPromise((resolve, reject) => {promiseArr.forEach((item, index) => {item.then((res) => {resArr[index] = res;var allResolve = promiseArr.every((_item) => {return _item.promiseState == "fulfilled";});// 判断传过来的数组中所有promise对象状态都已完成if (allResolve) {resolve(resArr);}}).catch((err) => {reject(err);});});});};
MyPromise.race = (promiseArr) => {let resArr = [];return new MyPromise((resolve, reject) => {promiseArr.forEach((item, index) => {item.then((res) => {resolve(res);}).catch((err) => {reject(err);});});});};
手写promise的化没有长时间的叙述的话不好将清楚,建议找到将promise源码的视频一步一步分析
教你如何手写一个Promise相关推荐
- Promise学习-手写一个promise
学习了Promise的A+规范,以及手写一个Promise后,我对Promise学到的结果. 平常也有用到过promise来处理异步,先回顾下promise的用法 new Promise((resol ...
- 手写一个promise用法_手写一个 Promise
1 js 的基本数据类型? 2 JavaScript 有几种类型的值? 3 什么是堆?什么是栈?它们之间有什么区别和联系? 4 内部属性 [Class] 是什么? 5 介绍 js 有哪些内置对象? 6 ...
- 手写一个promise用法_手写一个自己的 JavaScript Promise 类库
终于有时间写这篇文章了, ES2015 推出了JS 的 Promise ,而在没有原生支持的时候,我们也可以使用诸如 Promises/A+ 的库的帮助,在我们的代码里实现Promise 的支持: 如 ...
- JavaScript 怎么自己手写一个Promise
认真看完这篇文章, 您可以自己封装一个简易但功能相对齐全的Promise, 还可以加深对Promise的理解 建议 : 看这篇文章之前希望您 了解ES6的语法 [ 阮一峰老师的ES6入门 ] 了解Pr ...
- es6 --- 手写一个promise
一个promise实例: var getJSON = function(url) {var promise = new Promise(function(resolve, reject) {// XH ...
- 手写一个promise用法_手写一个Promise
JS面向对象 在JS中一切皆对象,但JS并不是一种真正的面向对象(OOP)的语言,因为它缺少类(class)的概念.虽然ES6引入了class和extends,使我们能够轻易地实现类和继承.但JS并不 ...
- Chat Top10 | 给面试官手写一个 Nacos,多少 K?
每周推荐的最新 Chat Top10 没有固定主题,仅仅是编辑部参考多方评分和反馈挑选出来的好文章,不一定适合你的口味,建议小心食用- 我们一起看下第三期 Chat Top10 都有哪些内容 ???? ...
- 深入Vue底层,手写一个vuex
深入底层,手把手教你写一个Vuex 1. Vuex是什么?什么场景下使用? 2. Vuex的基本使用 3. 手写一个vuex 1. Vuex是什么?什么场景下使用? Vuex是vue的一个插件,叫做状 ...
- 手写一个自己的 cli 并发布到 npm 上
手写一个自己的 cli 并发布到 npm 上 简介:大家平时肯定用过 vue-cli 或者 create-react-app,只需要敲简单的命令行,就可以生成一个完整的项目,非常好用.由于本人所在公司 ...
最新文章
- 卷积神经网络如何处理一维时间序列数据?
- linux mysql清除缓存_案例:通过shell脚本实现mysql数据备份与清理
- 武汉数字工程研究所计算机软件分数,武汉数字工程研究所2017考研成绩查询时间:2月16日...
- 如把联想电脑计算机图标放在桌面上,thinkpad电脑图标没了怎么恢复
- nginx php 源码安装,Nginx和php安装及配置一之编译安装nginx-1.8.0
- 【脑机接口】用人脑意念控制机器人即将落地
- sql数据库中有多列重复的数据查询
- C#用SqlCilent模式连接数据库实例
- 微信JS SDK Demo 官方案例
- 关于Redis的常识
- some tools
- 天猫手机一战成名? 塑造品牌 完胜京东
- 带本信息论看《三体》——信息论课程论文
- ruby 安装和使用
- hdu5956, The Elder (树型dp, 斜率优化)
- .NET/C# 阻止屏幕关闭,阻止系统进入睡眠状态
- 大数据开发hive数据库常用命令汇总
- 海淀服务器维修,服务器维修服务器维修防御升级、数据恢复、对接出错等维修服务...
- RocketMQ源码分析之request-reply特性
- 关系网络lbs的应用_LBS中国起步:探索空间关系的商业化
热门文章
- 计算机科学与技术审核评估专家,教育部本科教学审核评估专家喻祖国莅临我院开展深度访谈...
- 【循环链表】数据结构——单向循环链表和双向循环链表操作笔记
- java基础英语单词汇总,JAVA基础英语单词表(下)
- js获取元素高度比较
- 数字人相关的一些网站
- 记一次SQL server的驱动配置
- linux程序测试工具gprof,gprof-如何在Linux上分析多线程C ++应用程序?
- Tita绩效宝:80条有用的绩效考核评语
- 【嵌入式总复习】Linux管道详解——管道通信、无名管道、有名管道、具体应用示例
- 第四章:Python项目组织结构-第一节:包、模块以及__init__.py文件