promise的规范其实种类很多,我们最常用的是promise/A+

这篇文章会先将一个类似于promise的构造函数怎么写,网上很多教程并没有实现A+规范,只是看起来像而已

然后我们深入探究如何一步一步实现真正的promise/A+规范的要求。

首先我们实现一个简单的promise,这个promise类似于express的路由处理

express的路由处理以next的方式一层一层的进入, 直到不再next。这个很像promise呐,也是比较懒,没有去看源码,但试着实现一个那种异步,会发现其实蛮简单的。

ok,废话少说,先搞一个

需求

1. promise拥有then和catch方法

2. promise出错时调用catch,有两种错误,主动跑错可以用next(err)

3. promise的第一个参数为function, 第一个参数为next,其他参数可以传递到下一步。

然后我们要实现的功能如下

new Promise(next => {
setTimeout(() => {
console.log();
next(null, 2);
}, );
})
.then((next, arg) => {
setTimeout(() => {
console.log(arg);
next();
}, );
})
.then((next, arg) => {
setTimeout(() => {
console.log(arg);
next();
}, );
})
.catch(err => console.error(err));

实现

首先我们实现then和catch方法

  我们建立一个回调队列和一个出错回调1

  1)then里的东西都会被推进去

  2)catch会去替换默认的回调方法

  3)next函数会执行resovleCallbacks里的下一个方法

function Promise(execute) {
let resolveCallbacks = [];
let rejectCallbacks = err => console.error(err);
this.then = fn => {
resolveCallbacks.push(fn);
return this;
};
this.catch = fn => {
rejectCallback = fn;
return this;
}; execute(next); function next() {
const nextCallback = resolveCallbacks.shift();
nextCallback && nextCallback(next);
}
}

为了捕捉错误

  try {
execute(next);
} catch (err) {
rejectCallback(err);
}

我们添加如上的错误捕捉机制

假如果主动跑错就用next(err)

没有出错的话就next(null, arg1, arg2)这样传参

所以我们修改next方法

  function next(...args) {
if(args[]){
return rejectCallback(args[]);
}else{
const nextCallback = resolveCallbacks.shift();
try {
nextCallback && nextCallback(next, ...args.slice());
} catch (err) {
rejectCallback(err);
}
}
}

至此就实现完成了,很简单吧

game over

Promise/A+

但事实上一个伟大的promise/A+规范的实现可不止这么简单。

然后我们来看看一个promise/A+规范是什么样子的

1. 状态管理pendding fullfilled(resolved) rejected 三种

2. then返回一个新的promise, then的两个参数是function,是上一步的成功和失败的回调

3. 不同的promise可以接起来使用

以上是主要的规范 更加具体的看这里

要想实现promise/A+,首先要搞清楚它的工作原理

按照规范 最麻烦的是then方法的处理,

但是记住两点就Ok

1. 不同的promise的状态不同,所以then方法不可以返回this,而是应该返回一个新的promise

2. then的执行实在resolve完成后,所以在then方法里把onResolved方法修改为then的第一个参数

3. 在promise中then里的函数如果返回值是promise就必须等到promise执行完成才可以到下一步, 对此我们巧妙的运用promise的then,只要把resolve放到then里边就会延迟resolve的发生

return x.then(resolve);

4. 在promise中then里的函数如果返回值不是promise那就直接执行 然后resolve

5. executor应该是慢一点开始,所以用了setTimeout,因为首先需要执行的是then方法,待一切promise队列就绪后才可以开始。

6. 执行then的时候可能已经resolved了,那么这个时候就立即执行,如果还是pending状态的话那么就放到执行完成的回调函数里。

知道以上几点之后 就可以很轻松的看懂代码了

首先是构造函数

function Promise(executor) {
let onResolved = null;
let onRejected = null;
this.status = 'pending';
let self = this; let resolve = data => {
self.data = data || null;
self.status = 'resolved';
typeof onResolved === 'function' && onResolved(data);
} let reject = (err) => {
self.status = 'rejected';
typeof onRejected === 'function' && onRejected(data);
} this.then = onResolvedFn => { } executor(resolve, reject);
}

然后是then方法

    if (self.status === 'pending') {
console.log('promise is pending, add callback')
return new Promise(resolve => {
onResolved = data => {
let x = onResolvedFn(self.data)
if (x instanceof Promise) {
return x.then(resolve);
} else {
resolve();
}
}
})
} if (self.status === 'resolved') {
console.log('promise is resolved, execuate')
return new Promise(resolve => {
let x = onResolvedFn(self.data)
if (x instanceof Promise) {
return x.then(resolve);
} else {
resolve();
}
})
}

then方法实现后,然后我们实现一个Promise.resolve方法

Promise.resolve = data => new Promise(resolve => setTimeout(() => resolve(data)));

关于catch和promise的错误处理机制这里就不详细的写了,反正一切都为了简单看懂。

参考文章: https://zhuanlan.zhihu.com/p/21834559

promise的实现方式和运行机制的更多相关文章

  1. js运行机制及异步编程(一)

    相信大家在面试的过程中经常遇到查看执行顺序的问题,如setTimeout,promise,async await等等,各种组合,是不是感觉头都要晕掉了,其实这些问题最终还是考察大家对js的运行机制是否 ...

  2. Windows程序内部运行机制 转自http://www.cnblogs.com/zhili/p/WinMain.html

    一.引言 要想熟练掌握Windows应用程序的开发,首先需要理解Windows平台下程序运行的内部机制,然而在.NET平台下,创建一个Windows桌面程序,只需要简单地选择Windows窗体应用程序 ...

  3. JSP基础总结(运行机制、脚本元素、指令元素、动作元素)

    JSP的运行机制: 1.转译阶段:JSP页面转换成Servlet类: 2.请求阶段:Servlet类执行,将相应结果发送至客户端. 流程解释: 1.用户访问某个JSP页面 2.服务器找到相应的JSP页 ...

  4. Spark Streaming架构设计和运行机制总结

    本期内容 : Spark Streaming中的架构设计和运行机制 Spark Streaming深度思考 Spark Streaming的本质就是在RDD基础之上加上Time ,由Time不断的运行 ...

  5. PHP的运行机制与原理(底层) [转]

    说到php的运行机制还要先给大家介绍php的模块,PHP总共有三个模块:内核.Zend引擎.以及扩展层:PHP内核用来处理请求.文件流.错误处理等相关操作:Zend引擎(ZE)用以将源文件转换成机器语 ...

  6. 谈谈java的运行机制

    1.高级语言的运行机制 我们编程都是用的高级语言(写汇编和机器语言的大牛们除外),计算机不能直接理解高级语言,只能理解和运行机器语言,所以必须要把高级语言翻译成机器语言,计算机才能运行高级语言所编写的 ...

  7. (视频) 《快速创建网站》2.1 在Azure上创建网站及网站运行机制

    现在让我们开始一天的建站之旅. 本文是<快速创建网站>系列的第2篇,如果你还没有看过之前的内容,建议你点击以下目录中的章节先阅读其他内容再回到本文. 访问本系列目录,请点击:http:// ...

  8. Chrome扩展开发之二——Chrome扩展中脚本的运行机制和通信方式

    目录: 0.Chrome扩展开发(Gmail附件管理助手)系列之〇——概述 1.Chrome扩展开发之一——Chrome扩展的文件结构 2.Chrome扩展开发之二——Chrome扩展中脚本的运行机制 ...

  9. 简述JavaScript的运行机制

    想要理解JavaScript的运行机制,需要分别深刻理解以下几个点: · JavaScript的单线程机制 · 任务队列(同步任务和异步任务) · 事件和回调函数 · 定时器 · Event Loop ...

随机推荐

  1. css实现截取文本

    .ellipsis{ max-width: 260px; // 自定义 overflow: hidden; text-overflow: ellipsis; white-space: nowrap; ...

  2. 如何快速合并多个TXT文本内容

    工作中有时候需要合并很多文本内容,例如一些推送清单之类,一个一个打开去复制粘贴的话,少量还行,如果txt文本数据量大(10+M以上)且文件数量多(成百上千),这种方式就显得很低效了.具体要求如下:   ...

  3. 提高Modelsim仿真速度的方法(1) -- force

    假如主驱动时钟频率很高,因为要一个周期输出,仿真时间过长,仿真速度慢是自然. 但是仿真中,并不是每个驱动周期都是必要的,这时可以使用force命令把想要的信号提前制造出来. 事实上,对于使用到PLL的 ...

  4. C++内存字节对齐规则

    为什么要进行内存对齐以及对齐规则 C/C++—— 内存字节对齐规则 C++内存字节对齐规则

  5. LUOGU P1514 引水入城 (bfs)

    传送门 解题思路 拉了很长的战线,换了好几种写法终于过了..首先每个蓄水场一定是对沙漠造成连续一段的贡献,所以可以$bfs$出每种状态,然后做一次最小区间覆盖,但这样的复杂度有点高.就每次只搜那些比左 ...

  6. LUOGU P1438 无聊的数列 (差分+线段树)

    传送门 解题思路 区间加等差数列+单点询问,用差分+线段树解决,线段树里维护的就是差分数组,区间加等差数列相当于在差分序列中l位置处+首项的值,r+1位置处-末项的值,中间加公差的值,然后单点询问就相 ...

  7. go的单引号、双引号、反引号的区别

    Go语言的字符串类型string在本质上就与其他语言的字符串类型不同: Java的String.C++的std::string以及Python3的str类型都只是定宽字符序列 Go语言的字符串是一个用 ...

  8. Data too long for column

    一篇文章的正文,需要很多字数,默认就是255,不够 @Lob @Basic @Type(type = "text") @Column(name = "detail&quo ...

  9. Redis学习笔记01-分布式锁

    1.分布式锁的定义与理解 在并发任务中,当对数据执行修改和删除时为了防止多个任务同时拿到数据而产生的混乱,这时就要用到分布式锁来限制程序的并发执行. Redis分布式锁本质上要实现的目标就是在Redi ...

  10. linux 备份最近一天的文件

    #!/bin/bash #备份在最近一天修改的文件 #date 获取日期 +%Y-%m-%d 设置日期格式为yyyy-mm-dd的形式 BACKFILE=backup-$(date +%Y-%m-%d ...