Promise简单实现
前言
你可能知道,javascript的任务执行的模式有两种:同步和异步。异步模式非常重要,在浏览器端,耗时很长的操作(例如ajax请求)都应该异步执行,避免浏览器失去响应。
在异步模式编程中,我们经常使用回调函数。一不小心就可能写出以下这样的代码:
1 | //事件1 |
当你的需要异步执行的函数越来越多,你的层级也会越来越深。
这样的写法存在的缺点是:
- 不利于阅读
- 各个任务之间的高度耦合,难以维护
- 对异常的处理比较难
用Promise可以避免这种回调地狱,可以写成这样
1 | //事件1 |
在市面上有许多库都实现了Promise,例如:Q.js 、when.js ,es6也将Promise纳入了标准中
es6 的 Promise使用方法可以参考阮一峰的 http://es6.ruanyifeng.com/#docs/promise ,我就不在做具体介绍
接下来,我们模仿ES6的promise,一步一步来实现一个简单版的Promise。
构造函数
我们使用Promise的时候,
1 | const promise = new Promise((resolve, reject)=>{ |
Promise是一个构造函数,接收一个函数,函数里有两个参数,resolve、reject。
我们可以这样子实现:
1 | class PromiseA { |
then方法
promise中,用的最频繁的就是then方法,then方法有两个参数,一个是promise成功时候的回调,一个是失败的回调。实现方式为:
1 | class PromiseA { |
then方法有以下几个特性:
- 支持链式操作
- 每次then方法都是返回新的Promise
- 当前promise的状态通过返回值传递给下一个promise
- 错误冒泡,即如果当前promise没有提供onReject方法,会把错误冒泡到下一个promise,方便处理
1 | then(onResolve,onReject){ |
这样我们就实现了一个简单版的then方法了
加强版then
上面的实现,模拟了then方法的逻辑,但是还有一些缺点:
- then方法只能添加一个,例如
1 | let p = new PromiseA((resolve)=>{setTimeout(()=>{resolve(1)},0)}); |
- promise没有状态,当promsie在添加then的时候已经完成了,没法得到结果
- 没有实现:如果上一个promise的返回值也是一个Promise对象时,则会等到这个Promise resolve的时候才执行下一个
为了解决第一点,引入了事件监听,简单的实现如下:
1 | export default class EventEmitter { |
所以进一步对PromiseA进行改造:
1 | const STATUS = { |
到这里,我们的then方法基本就完成了。
最后还有一个小知识点,就是执行时机的问题:
1 | setTimeout(function(){ |
promise.then,是异步的,属于microtask,执行时机是本次事件循环结束之前,而setTimeout是macrotask,执行时机是在下一次事件循环的开始之时
实现这个功能,我利用了第三方库 microtask 来模拟。所以PromiseA修改为:
1 | resolve(value) { |
到此为止,我们的then方法已经大功告成了。最困难的一步已经解决了
catch
Promise跟普通回调的一大优势就是异常处理,我们推荐使用Promise的时候,总是使用catch来代替then的第二个参数。即是:
1 | //bad |
接下来让我们实现catch方法:
1 | catch(reject) { |
哈哈~ , 你没看错。你已经实现了catch方法
all方法
Promise.all是一个很好用的方法。接受一个promise数组,然后等到所有的异步操作都完成了,就返回一个数组,包含对应的值
具体实现如下:
1 | static all(promiseList = []) { |
race方法
race方法为竞速,第一执行完的为准。所以只需循环一遍执行就可以了。当有第一个将Promise的状态改变成fullfilled或reject之后,其他的就都无效了
1 | static race(promiseList = []) { |
最后,我们实现了一个简单版的promise, 还有一些其他的方法在这里没有讲到。感兴趣的朋友可以自行去研究哈~
附上代码完整的实现 : https://github.com/chen4342024/Learning/tree/master/learn_js/learn_lib/learn_promise/src/js
关于作者:
AndyChen,前端开发,Hybrid App
联系方式:374664805@qq.com
博客:http://chen4342024.github.io/本文为原创文章,因此转载请保留原出处
本文永久链接:http://chen4342024.github.io/2018/01/22/promise简单实现/