我们手写一个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. Django高级实战 开发企业级问答网站✍✍✍

    Django高级实战 开发企业级问答网站 1. 创建项目与app 创建项目 django-admin startproject firstsite 创建app python manage.py sta ...

  2. Python调用DLL动态链接库——ctypes使用

    最近要使用python调用C++编译生成的DLL动态链接库,因此学习了一下ctypes库的基本使用. ctypes是一个用于Python的外部函数库,它提供C兼容的数据类型,并允许在DLL或共享库中调 ...

  3. 2019-8-31-win2d-通过-CanvasActiveLayer-画出透明度和裁剪

    title author date CreateTime categories win2d 通过 CanvasActiveLayer 画出透明度和裁剪 lindexi 2019-08-31 08:52 ...

  4. (转)nginx下基于ThinkPHP框架的网站url重写

    nginx下基于ThinkPHP框架的网站url重写nginx下的基于thinkphp的应用的url重写,需了解thinkphp的各种url格式参数的处理逻辑以及nginx重写的原理.简单点说,无论哪 ...

  5. SQLite C++操作类

    为了方便SQLite的使用,封装了一个SQLite的C++类,同时支持ANSI 和UNICODE编码.代码如下:   头文件(SQLite.h) [cpp] view plaincopy /***** ...

  6. python dict 实现swich

    使用dict实现swich,通过不同的键映射不同的函数. swich = { 'hour1':pred.getper1htable, 'hour6':pred.getper6htable, 'hour ...

  7. mysql 主从,双主同步

    1.创建用户并设置远程访问授权 1). A上添加: //ip地址为B的ip地址,用于B访问 ' with grant option; 2). B上添加://ip地址为A的ip地址,用于A访问 ' wi ...

  8. linux mysql备份shell

    #!/bin/bash # Shell script to backup MySql database # Author: Henry he # Last updated: -- # crontab ...

  9. 富文本vue-quill-editor修改图片上传方法

    富文本vue-quill-editor修改图片上传方法 HTML 代码 HTML codes <!-- 上传的组件 --> <upload style="display:n ...

  10. 观察属性$watch

    <!DOCTYPE html> <html lang="zh"> <head> <title></title> < ...