我们手写一个Promise/A+规范,然后安装测试脚本,以求通过这个规范。

//Promise/A+源代码
// new Promise时,需要传递一个executor执行器,执行器立即执行
// executor接受两个参数,分别是resolve和reject
// promise只能从pending到rejected,或者从pending到fulfilled
// promise的状态一旦确认,就不会再改变
// promise有then方法,then接受两个参数,分别是promise成功的回调onFulfilled
// 和promise失败的回调 onRejected
// 如果调用then时,promise已经成功,则执行onFulfilled,并将promise值作为参数传递进去
// 如果promise已经失败,那么执行onRejected并把promise失败的原因作为参数传递进去
// 如果promise状态是pending,需要将onFulfilled和onRejected函数存放起来,等待状态确定后,再一次将对应的函数执行(发布)
// then的参数onFulfilled和onRejected可以缺省
// promise可以then多次,promise的then方法返回一个promise
// 如果then返回的是一个结果,那么就把这个结果作为参数,传递给下一个then的成功的回调onFulfilled
// 如果then中抛出了异常,那么就会把这个异常作为参数,传递给下一个失败的回调 onRejected
// 如果then返回的是一个promise,那么需要等这个promise,那么会等这个promise执行完,promise如果成功
// 就走下一个then的成功,如果失败,就走下一个then的失败
//pending状态,可以认为是一种中间状态
const PENDING = 'pending';
// fullfilled完成状态,可以认为是成功回调了的状态
const FULFILLED = 'fullfilled';
// reject即为拒绝状态,即失败的状态
const REJECTED = 'reject';
// executor是一个执行器
function Promise(executor){
let self = this;
self.status = PENDING;
self.onFulfilled = [];//成功的回调
self.onRejected = [];//失败的回调
// PromiseA+ 2.1
function resolve(value){
if(self.status === PENDING){
self.status = FULFILLED;
self.value = value;
self.onFulfilled.forEach(fn=>fn());//PromiseA+ 2.2.6.1
}
}
function reject(reason){
if(self.status===PENDING){
self.status = REJECTED;
self.reason = reason;
self.onRejected.forEach(fn=>fn());//PromiseA+ 2.2.6.2
}
}
try{
executor(resolve,reject)
}catch(e){
reject(e)
}
}
// then必须返回一个promise
Promise.prototype.then = function(onFulfilled,onRejected){
// PromiseA+ 2.2.1/PromiseA+ 2.2.5/PromiseA+ 2.2.7.3/PromiseA+2.2.7.4
onFulfilled = typeof onFulfilled ==='function'?onFulfilled:value =>value;
onRejected = typeof onRejected === 'function'?onRejected:reason=>{throw reason};
let self = this;
//PromiseA+ 2.2.7
let Promise2 = new Promise((resolve,reject)=>{
if(self.status===FULFILLED){
//PromiseA+2.2.2
// Promise A+2.2.4----setTimeout
setTimeout(()=>{
try{
let x = onFulfilled(self.value);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
//PromiseA+2.2.7.2
reject(e)
}
});
}else if(self.status === REJECTED){
// PromiseA+ 2.2.3
setTimeout(()=>{
try{
let x = onRejected(self.reason);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
})
}else if(self.status===PENDING){
self.onFulfilled.push(()=>{
setTimeout(()=>{
try{
let x = onFulfilled(self.value);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
});
});
}
});
return promise2;
}
function resolvePromise(promise2,x,resolve,reject){
let self = this;
//PromiseA+ 2.3.1
if(promise2===x){
reject(new TypeError('changing cycle'));
}
if(x && typeof x ==="object"|| typeof x ==='function'){
let used;//PromiseA+ 2.3.3.3.3//只能调用一次
try{
let then = x.then;
if(typeof then === 'function'){
//PromiseA+2.3.3
then.call(x,(y)=>{
// PromiseA+ 2.3.3.1
if(used)return;
used = true;
resolvePromise(promise2,y,resolve,reject);
},(r)=>{
//PromiseA+2.3.3.2
if(used)return;
used = true;
reject(r)
});
}else{
//PromiseA+ 2.3.3.4
if(used)return;
used = true;
reject(x);
}
}catch(e){
//PromiseA+ 2.3.3.2
if(used)return;
used = true;
reject(e);
}
}else{
//PromiseA+ 2.3.3.4
resolve(x);
}
}
module.exports = Promise;

我们可以用专门的测试脚本测试所编写的代码是否符合PromiseA+的规范。

在上面的promise实现的代码中,增加一下代码

Promise.defer = Promise.deferred = function(){
let dfd = {};
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}

安装测试脚本

npm install -g promises-aplus-tests

如果当前的promise源码的文件名为promise.js

那么在对应的目录执行以下命令:

promises-aplus-tests promise.js

promises-aplus-tests中共有872条测试用例。以上代码,可以完美通过所有用例。

本文借鉴自:https://blog.csdn.net/liuyan19891230/article/details/88385973

这篇博客是ES6的写法:https://blog.csdn.net/weixin_41436338/article/details/79806033

有空就多学多看源码,你看那么多人那么牛逼啊

Promise的源码实现(符合Promise/A+规范)的更多相关文章

  1. Promise的源码实现(完美符合Promise/A+规范)

    Promise是前端面试中的高频问题,我作为面试官的时候,问Promise的概率超过90%,据我所知,大多数公司,都会问一些关于Promise的问题.如果你能根据PromiseA+的规范,写出符合规范 ...

  2. JS魔法堂: Native Promise Only源码剖析

    一, 前言 深入学习Promise的朋友应该都看过<深入理解Promise五部曲>这一系列的文章, 以解除回调地狱之外的观点来剖析Promise更多的内涵,确实十分精彩. Part 1: ...

  3. promise/bluebird源码

    本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/bluebirdsource 本博客同步在http://www.cnb ...

  4. 异步解决方案promise及源码实现

    js语言的特性,造就了特别的异步处理方式,我记得以前用的最多的就是回调函数,那个时候写jquery的ajax时候,特别喜欢写这种代码: $.ajax({ method:'get', url:" ...

  5. Django day24 cbv和APIView的源码分析 和 resful的规范

    一:cbv的源码分析 1.CBV和FBV的区别: - Class Base View   CBV(基于类的视图) - Function Base View   FBV(基于函数的视图) 2.as_vi ...

  6. [编织消息框架][netty源码分析]9 Promise 实现类DefaultPromise职责与实现

    netty Future是基于jdk Future扩展,以监听完成任务触发执行Promise是对Future修改任务数据DefaultPromise是重要的模板类,其它不同类型实现基本是一层简单的包装 ...

  7. jQuery之Deferred源码剖析

    一.前言 大约在夏季,我们谈过ES6的Promise(详见here),其实在ES6前jQuery早就有了Promise,也就是我们所知道的Deferred对象,宗旨当然也和ES6的Promise一样, ...

  8. jquery源码解析:jQuery延迟对象Deferred(工具方法)详解2

    请接着上一课继续看. $.Deferred()方法中,有两个对象,一个是deferred对象,一个是promise对象. promise对象有以下几个方法:state,always,then,prom ...

  9. promise源码解析

    前言 大部分同学对promise,可能还停留在会使用es6的promise,还没有深入学习.我们都知道promise内部通过reslove.reject来判断执行哪个函数,原型上面的then同样的,也 ...

随机推荐

  1. Neo4j全文检索

    全文检索基本概念 搜索 搜索这个行为是用户与搜索引擎的一次交互过程,用户需要找一些数据,他提供给搜索引擎一些约束条件.搜索引擎通过约束条件抽取一些结果给用户 搜索引擎 搜索引擎存在的目的是存储,查找和 ...

  2. js 实现加载百分比效果

    效果: html: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> < ...

  3. ON_WM_TIMER() void (__cdecl xx::* )(UINT)”转换为“void (__cdecl CWnd::* )(UINT_PTR)

     ON_WM_TIMER()在编译器从32位转换为64位的时候, 出现的问题; class CFlatComboBox : public CComboBox   (基类为CWnd) 为了重载CWnd的 ...

  4. GNU GRUB引导的默认启动项是ubuntu

    安装了ubuntu16.04后,GNU GRUB引导的默认启动项是ubuntu,如果希望默认启动项是windows,修改方法如下: step1. 进入Ubuntu系统,打开终端,输入 sudo ged ...

  5. C++ 系列:C++ 内存布局

    1 前言 了解你所使用的编程语言究竟是如何实现的,对于C++程序员可能特别有意义.首先,它可以去除我们对于所使用语言的神秘感,使我们不至于对于编译器干的活感到完全不可思议:尤其重要的是,它使我们在De ...

  6. Java虚拟机性能管理神器 - VisualVM(7) 排查JAVA应用程序线程泄漏【转】

    Java虚拟机性能管理神器 - VisualVM(7) 排查JAVA应用程序线程泄漏[转] 标签: javajvm线程泄漏 2015-03-11 19:47 1098人阅读 评论(0) 收藏 举报   ...

  7. 廖雪峰Java11多线程编程-3高级concurrent包-8CompletableFuture

    使用Future可以获得异步执行结果 Future<String> future = executor.submit(task); String result = future.get() ...

  8. windows下VisualSVN Server搭建

    转自:https://www.cnblogs.com/shuilangyizu/p/10365604.html 使用 VisualSVN Server来实现主要的 SVN功能则要比使用原始的 SVN和 ...

  9. System.Web.Mvc.EmptyResult.cs

    ylbtech-System.Web.Mvc.EmptyResult.cs 1.程序集 System.Web.Mvc, Version=5.2.3.0, Culture=neutral, Public ...

  10. Java MySQL 批量查询数据,每次查询10条

    因为 数据量比较多, 比如每次 /** * 批量查询 * @param sourList * @param batchCount * @param userMapper * @return */ pu ...