手写一款符合Promise/A+规范的Promise
手写一款符合Promise/A+规范的Promise
长篇预警!有点长,可以选择性观看。如果对Promise源码不是很清楚,还是推荐从头看,相信你认真从头看到尾,并且去实际操作了,肯定会有收获的。主要是代码部分有点多,不过好多都是重复的,不必担心
Promise的一些用法在此不多赘述,本篇主要带领你手写一个Promise源码,学完你就会发现:Promise没有你想象中的那么难
本篇大概分为以下步骤
- 实现简单的同步Promise
- 增加异步功能
- 增加链式调用then
- 增加catch finally方法
- 增加all race 等方法
- 实现一个promise的延迟对象defer
- 最终测试
实现简单的同步Promise
先大概说一下基本概念:
Promise内部维护着三种状态,即pending,resolved和rejected。初始状态是pending,状态可以有pending--->relolved,或者pending--->rejected.不能从resolve转换为rejected 或者从rejected转换成resolved.
即 只要Promise由pending状态转换为其他状态后,状态就不可变更。
ok.知道了这些后,我们开始手撸代码:
注意观看序号 1 2 3 4 5 ...
function Promise(executor){
let that = this;
/** 2 定义初始的一些变量 */
that.status = 'pending';
that.value = null;
that.reason = null;
/** 3 定义初始的成功和失败函数 */
function resolve(value){
/** 4 判断状态是不是初始状态pending
* 是就转换状态 否则不转换
* 确保状态的变化后的不可变性 */
if(that.status === 'pending'){
that.status = 'resolved';
that.value = value;
}
}
function reject(reason){
/** 5 同上 */
if(that.status === 'pending'){
that.status = 'rejected';
that.reason = reason;
}
}
/**
* 1 Promise中首先传了一个executor,它是一个函数
* executor函数中又传了两个函数,分别是resolve和reject
* 很显然 resolve是成功回调,reject是失败的回调
*/
executor(resolve,reject);
}
/** 6 在Promise原型上面定义then方法
* then方法上面有两个回调 一个是成功后的方法 另一个是失败后的方法
* 根据成功或失败的状态去执行相关成功onFilfulled()或者失败onRejected()的回调方法
*/
Promise.prototype.then = function(onFilfulled,onRejected){
let that = this;
if(that.status === 'resolved'){
/** 7 如果状态已经变更为resolved
* 说明resolve方法已经被调用
* 那么此时就执行成功的回调函数onFilfulled
* 并传入参数 that.value
* */
onFilfulled(that.value);
}
if(that.status === 'rejected'){
/** 8 同上
* 传入参数 that.reason
*/
onRejected(that.reason);
}
}
module.exports = Promise;
通过require()引入手撸的Promise
let Promise = require('./myPromise');
let p1 = ()=>{
return new Promise((resolve,reject)=>{
resolve('success.1');
});
}
p1().then((data)=>{
console.log(data); // 打印 success.1
},(err)=>{
console.log(err);
});
ok.经调用发现 此代码可以实现部分Promise的功能,但仅仅是同步下才有效果。
那异步呢? 别急这就来~:
增加异步功能
注意观看序号 1 2 3 4 5 ...
function Promise(executor){
let that = this;
that.status = 'pending';
that.value = null;
that.reason = null;
/** 1 因为异步不是立即执行 状态不会变更 成功或失败的回调函数也不会执行
* 所以先定义好存放成功或失败回调函数的数组
* 以便将成功或失败的回调函数先保存起来
* */
that.onFilFulledCallbacks = [];
that.onRejectedCallbacks = [];
function resolve(value){
if(that.status === 'pending'){
that.status = 'resolved';
that.value = value;
/** 3 发布
* 等待状态发生变更
* 状态变更后 立即执行之前存放在相应数组中所有的成功或失败的回调函数
* 即 发布
*/
that.onFilFulledCallbacks.forEach((fn)=>{
fn();
});
}
}
function reject(reason){
if(that.status === 'pending'){
that.status = 'rejected';
that.reason = reason;
/** 4 同上 */
that.onRejectedCallbacks.forEach((fn)=>{
fn();
});
}
}
executor(resolve,reject);
}
Promise.prototype.then = function(onFilfulled,onRejected){
let that = this;
if(that.status === 'resolved'){
onFilfulled(that.value);
}
if(that.status === 'rejected'){
onRejected(that.reason);
}
/** 2 订阅
* 因为是异步 状态当时并没有立即变更 所以状态还是pending
* 此时需要把成功或者失败的回调函数存放到对应的数组中
* 等待状态变更时 再从数组中拿出来去执行
* 即 订阅
* *存放数组时 为了执行时方便 需要把回调函数的外层包裹一层空函数
*/
if(that.status === 'pending'){
that.onFilFulledCallbacks.push(function(){
onFilfulled(that.value);
});
}
if(that.status === 'pending'){
that.onRejectedCallbacks.push(function(){
onRejected(that.reason);
});
}
}
module.exports = Promise;
代码测试:
let Promise = require('./myPromise');
let p1 = ()=>{
return new Promise((resolve,reject)=>{
setTimeout(function(){
resolve('success.1');
// reject('fail.');
},1500);
});
}
p1().then((data)=>{
console.log(data); // success.1
},(err)=>{
console.log(err);
});
可以看到 1.5s后 执行了resolve() 并打印了success.1,至此,我们实现了异步的Promise.其实这里的实现异步的思想就是发布订阅.
en~ok.高能预警
手写一款符合Promise/A+规范的Promise的更多相关文章
- 一起学习造轮子(一):从零开始写一个符合Promises/A+规范的promise
本文是一起学习造轮子系列的第一篇,本篇我们将从零开始写一个符合Promises/A+规范的promise,本系列文章将会选取一些前端比较经典的轮子进行源码分析,并且从零开始逐步实现,本系列将会学习Pr ...
- 如何手写一款KOA的中间件来实现断点续传
本文实现的断点续传只是我对断点续传的一个理解.其中有很多不完善的地方,仅仅是记录了一个我对断点续传一个实现过程.大家应该也会发现我用的都是一些H5的api,老得浏览器不会支持,以及我并未将跨域考虑入内 ...
- 一步一步实现一个Promise A+规范的 Promise
2015年6月,ES2015(即ES6)正式发布后受到了非常多的关注.其中很重要的一点是 Promise 被列为了正式规范. 在此之前很多库都对异步编程/回调地狱实现了类 Promise 的应对方案, ...
- 如何手写一款SQL injection tool?
0×01 前言 我想在FreeBuf上出没的人一般都是安全行业的,或者说是安全方面的爱好者,所以大家对sql注入应该都比较了解,反正我刚入门的时候就是学的这些:sql注入.xss之类的.sql注入从出 ...
- [手写系列] 带你实现一个简单的Promise
简介 学习之前 需要先对Promise有个基本了解哦,这里都默认大家都是比较熟悉Promise的 本次将带小伙伴们实现Promise的基本功能 Promise的基本骨架 Promise的then Pr ...
- 手写符合Promise/A+规范的Promise
const PENDING = "pending"; const RESOLVED = "resolved"; const REJECTED = "r ...
- 手写基于Promise A+规范的Promise
const PENDING = 'pending';//初始态const FULFILLED = 'fulfilled';//初始态const REJECTED = 'rejected';//初始态f ...
- 参考KOA,5步手写一款粗糙的web框架
我经常在网上看到类似于KOA VS express的文章,大家都在讨论哪一个好,哪一个更好.作为小白,我真心看不出他两who更胜一筹.我只知道,我只会跟着官方文档的start做一个DEMO,然后我就会 ...
- 手写一个Promise/A+,完美通过官方872个测试用例
前段时间我用两篇文章深入讲解了异步的概念和Event Loop的底层原理,然后还讲了一种自己实现异步的发布订阅模式: setTimeout和setImmediate到底谁先执行,本文让你彻底理解Eve ...
随机推荐
- 遇到OutOfMemoryException异常了
遇到OutOfMemoryException异常了 2008-11-28 09:52 asp.net做的售后服务系统运行了快1年了,昨天在做全年数据导出的时候出现OutOfMemoryExceptio ...
- 【BZOJ2424】[HAOI2010]订货 最小费用流
[BZOJ2424][HAOI2010]订货 Description 某公司估计市场在第i个月对某产品的需求量为Ui,已知在第i月该产品的订货单价为di,上个月月底未销完的单位产品要付存贮费用m,假定 ...
- 【BZOJ3436】小K的农场 差分约束
[BZOJ3436]小K的农场 Description 背景 小K是个特么喜欢玩MC的孩纸... 描述 小K在MC里面建立很多很多的农场,总共n个,以至于他自己都忘记了每个农场中种植作物的具体数量了, ...
- Servlet3.0文件上传
Servelt3.0文件上传作为一种便捷的文件上传方式很是值得我们去应用的 1.Servlet3.0文件上传使用步骤 浏览器端的要求 表单的提交方法必须是post 必须有一个文件上传组件 <in ...
- 160614、Eclipse下JRebel6.2.0热部署插件安装、破解及配置
标签: 这两天在做后台管理系统,前端框架用Bootstrap,后端用SpringMVC+Velocity.在开发过程中,经常需要对界面进行微调,调整传参等,每次更改一次java代码,就得重新部署一次, ...
- Javascript-可定义位数的十进制转二进制
// 十进制转二进制 function binary (num, Bits) { var d = parseInt(num / 2) var resArry = [num % 2] for(; d ! ...
- 【Python算法】哈希存储、哈希表、散列表原理
哈希表的定义: 哈希存储的基本思想是以关键字Key为自变量,通过一定的函数关系(散列函数或哈希函数),计算出对应的函数值(哈希地址),以这个值作为数据元素的地址,并将数据元素存入到相应地址的存储单元中 ...
- Windows平台下解决Oracle12c使用PDB数据库创建SDE的问题 分类: oracle sde 2015-06-12 11:03 88人阅读 评论(0) 收藏
Windows平台下解决Oracle12c使用PDB数据库创建SDE的问题 Oracle 12C中引入了CDB与PDB的新特性,在ORACLE 12C数据库引入的多租用户环境(Multitenant ...
- ajax数据提交数据的三种方式和jquery的事件委托
ajax数据提交数据的三种方式 1.只是字符串或数字 $.ajax({ url: 'http//www.baidu.com', type: 'GET/POST', data: {'k1':'v1'}, ...
- Favorite Donut--hdu5442(2015年长春网选赛,kmp,最大表示法)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5442 打比赛的时候还没学kmp更没有学最大最小表示法,之后做完了kmp的专题,学了它们,现在再来做这道 ...