源码: https://github.com/dream2023/blog/tree/master/promise
es6 知识: http://es6.ruanyifeng.com
this 问题: https://juejin.im/post/59bfe84351882531b730bac2
Promise 基础教学: https://www.imooc.com/learn/949
Promise/A+规范原文: https://promisesaplus.com/
Promise/A+规范译文: http://www.ituring.com.cn/article/66566
参考文章 BAT 前端经典面试问题:史上最最最详细的手写 Promise 教程: https://juejin.im/post/5b2f02cd5188252b937548ab
参考文章 手写实现满足 Promise/A+ 规范的 Promise: https://www.jianshu.com/p/8d5c3a9e6181
vscode 编辑器: https://code.visualstudio.com/
vscode 代码运行插件 code-runner: https://marketplace.visualstudio.com/items?itemName=formulahendry.code-runner
我们工作中免不了运用promise用来解决异步回调问题。平时用的很多库或者插件都运用了promise 例如axios、fetch等等。但是你知道promise是咋写出来的呢?
别怕~这里有本promisesA+规范,便宜点10元卖给你了。
首先呢,promise肯定是一个类,我们就用class来声明。
new Promise((resolve, reject)=>{})
,所以传入一个参数(函数),秘籍里叫他executor,传入就执行。 class Promise{
// 构造器
constructor(executor){
// 成功
let resolve = () => { };
// 失败
let reject = () => { };
// 立即执行
executor(resolve, reject);
}
}
Promise存在三个状态(state)pending、fulfilled、rejected
pending(等待态)为初始态,并可以转化为fulfilled(成功态)和rejected(失败态)
成功时,不可转为其他状态,且必须有一个不可改变的值(value)
失败时,不可转为其他状态,且必须有一个不可改变的原因(reason)
new Promise((resolve, reject)=>{resolve(value)})
resolve为成功,接收参数value,状态改变为fulfilled,不可再次改变。
new Promise((resolve, reject)=>{reject(reason)})
reject为失败,接收参数reason,状态改变为rejected,不可再次改变。
若是executor函数报错 直接执行reject();
于是乎,我们获得以下代码
class Promise{
constructor(executor){
// 初始化state为等待态
this.state = 'pending';
// 成功的值
this.value = undefined;
// 失败的原因
this.reason = undefined;
let resolve = value => {
// state改变,resolve调用就会失败
if (this.state === 'pending') {
// resolve调用后,state转化为成功态
this.state = 'fulfilled';
// 储存成功的值
this.value = value;
}
};
let reject = reason => {
// state改变,reject调用就会失败
if (this.state === 'pending') {
// reject调用后,state转化为失败态
this.state = 'rejected';
// 储存失败的原因
this.reason = reason;
}
};
// 如果executor执行报错,直接执行reject
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
}
class Promise{
constructor(executor){...}
// then 方法 有两个参数onFulfilled onRejected
then(onFulfilled,onRejected) {
// 状态为fulfilled,执行onFulfilled,传入成功的值
if (this.state === 'fulfilled') {
onFulfilled(this.value);
};
// 状态为rejected,执行onRejected,传入失败的原因
if (this.state === 'rejected') {
onRejected(this.reason);
};
}
}
这下武学初成,可以对付对付江湖小杂毛了,但是对于带setTimeout的江洋大盗还是没辙。
现在基本可以实现简单的同步代码,但是当resolve在setTomeout内执行,then时state还是pending等待状态 我们就需要在then调用的时候,将成功和失败存到各自的数组,一旦reject或者resolve,就调用它们
类似于发布订阅,先将then里面的两个函数储存起来,由于一个promise可以有多个then,所以存在同一个数组内。
// 多个then的情况
let p = new Promise();
p.then();
p.then();
成功或者失败时,forEach调用它们
class Promise{
constructor(executor){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
// 成功存放的数组
this.onResolvedCallbacks = [];
// 失败存放法数组
this.onRejectedCallbacks = [];
let resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
// 一旦resolve执行,调用成功数组的函数
this.onResolvedCallbacks.forEach(fn=>fn());
}
};
let reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
// 一旦reject执行,调用失败数组的函数
this.onRejectedCallbacks.forEach(fn=>fn());
}
};
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled,onRejected) {
if (this.state === 'fulfilled') {
onFulfilled(this.value);
};
if (this.state === 'rejected') {
onRejected(this.reason);
};
// 当状态state为pending时
if (this.state === 'pending') {
// onFulfilled传入到成功数组
this.onResolvedCallbacks.push(()=>{
onFulfilled(this.value);
})
// onRejected传入到失败数组
this.onRejectedCallbacks.push(()=>{
onRejected(this.reason);
})
}
}
}
我门常常用到new Promise().then().then()
,这就是链式调用,用来解决回调地狱
由于Promise中转态不可以改变,所以要实现链式调用,那么then方法执行后的返回值必须是一个新的实例。
promise的 then 方法之后会继续返回一个promise对象
例子如下:
let test = new Promise((resolve, reject) => {
let random = Math.random()
if (random > 0.5) {
resolve('大于0.5')
} else {
reject('小于等于0.5')
}
})
let p = test.then((result) => {
console.log(result)
return result
}).catch((result) => {
console.log(result)
return result
}).then((result) => {
console.log(result)
return result
}).then((result) => {
console.log('last', result)
})
console.log(p)
使用node执行后的结果如下:
这是p: Promise { <pending> }
大于0.5
大于0.5
last 大于0.5
从结果我们可以看出:使用then方法之后会返回一个promise对象,可以继续用then方法调用,再次调用所获取的参数是上个then方法return的内容;
上面的这个例子只是一种情况,即第一次then之后所返回promise不会出现reject的状态,但如果我们在第一次then之后再手动返回一个可能包含reject状态的promise的话,那么错误链式调用过程中的错误处理就是大问题了,因为第二次then是不带错误处理机制的,这就要求我们在promise里的reject状态里直接写上对应的错误处理机制。
//resolve方法
Promise.resolve = function(val){
return new Promise((resolve,reject)=>{
resolve(val)
});
}
//reject方法
Promise.reject = function(val){
return new Promise((resolve,reject)=>{
reject(val)
});
}
//race方法
Promise.race = function(promises){
return new Promise((resolve,reject)=>{
for(let i=0;i<promises.length;i++){
promises[i].then(resolve,reject)
};
})
}
//all方法(获取所有的promise,都执行then,把结果放到数组,一起返回)
Promise.all = function(promises){
let arr = [];
let i = 0;
function processData(index,data){
arr[index] = data;
i++;
if(i == promises.length){
resolve(arr);
};
};
return new Promise((resolve,reject)=>{
for(let i=0;i<promises.length;i++){
promises[i].then(data=>{
processData(i,data);
},reject);
};
});
}
1、为了达成链式,我们默认在第一个then里返回一个promise。秘籍规定了一种方法,就是在then里面返回一个新的promise,称为promise2:promise2 = new Promise((resolve, reject)=>{})
2、当我们在第一个then中return
了一个参数(参数未知,需判断)。这个return出来的新的promise就是onFulfilled()或onRejected()的值
秘籍则规定onFulfilled()或onRejected()的值,即第一个then返回的值,叫做x,判断x的函数叫做resolvePromise
return
的对象)、resolve、reject class Promise{
constructor(executor){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onResolvedCallbacks.forEach(fn=>fn());
}
};
let reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn=>fn());
}
};
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled,onRejected) {
// 声明返回的promise2
let promise2 = new Promise((resolve, reject)=>{
if (this.state === 'fulfilled') {
let x = onFulfilled(this.value);
// resolvePromise函数,处理自己return的promise和默认的promise2的关系
resolvePromise(promise2, x, resolve, reject);
};
if (this.state === 'rejected') {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
};
if (this.state === 'pending') {
this.onResolvedCallbacks.push(()=>{
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
})
this.onRejectedCallbacks.push(()=>{
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
})
}
});
// 返回promise,完成链式
return promise2;
}
}
秘籍规定了一段代码,让不同的promise代码互相套用,叫做resolvePromise
let p = new Promise(resolve => {
resolve(0);
});
var p2 = p.then(data => {
// 循环引用,自己等待自己完成,一辈子完不成
return p2;
})
1、判断x
let then = x.then
2、当x是对象或者函数(默认promise) function resolvePromise(promise2, x, resolve, reject){
// 循环引用报错
if(x === promise2){
// reject报错
return reject(new TypeError('Chaining cycle detected for promise'));
}
// 防止多次调用
let called;
// x不是null 且x是对象或者函数
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
// A+规定,声明then = x的then方法
let then = x.then;
// 如果then是函数,就默认是promise了
if (typeof then === 'function') {
// 就让then执行 第一个参数是this 后面是成功的回调 和 失败的回调
then.call(x, y => {
// 成功和失败只能调用一个
if (called) return;
called = true;
// resolve的结果依旧是promise 那就继续解析
resolvePromise(promise2, y, resolve, reject);
}, err => {
// 成功和失败只能调用一个
if (called) return;
called = true;
reject(err);// 失败了就失败了
})
} else {
resolve(x); // 直接成功即可
}
} catch (e) {
// 也属于失败
if (called) return;
called = true;
// 取then出错了那就不要在继续执行了
reject(e);
}
} else {
resolve(x);
}
}
1、秘籍规定onFulfilled,onRejected都是可选参数,如果他们不是函数,必须被忽略
value => value
reason => throw err
2、秘籍规定onFulfilled或onRejected不能同步被调用,必须异步调用。我们就用setTimeout解决异步问题 class Promise{
constructor(executor){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onResolvedCallbacks.forEach(fn=>fn());
}
};
let reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn=>fn());
}
};
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled,onRejected) {
// onFulfilled如果不是函数,就忽略onFulfilled,直接返回value
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
// onRejected如果不是函数,就忽略onRejected,直接扔出错误
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
let promise2 = new Promise((resolve, reject) => {
if (this.state === 'fulfilled') {
// 异步
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === 'rejected') {
// 异步
setTimeout(() => {
// 如果报错
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === 'pending') {
this.onResolvedCallbacks.push(() => {
// 异步
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
// 异步
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
});
};
});
// 返回promise,完成链式
return promise2;
}
}
顺便附赠catch和resolve、reject、race、all方法
class Promise{
constructor(executor){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onResolvedCallbacks.forEach(fn=>fn());
}
};
let reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn=>fn());
}
};
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled,onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
let promise2 = new Promise((resolve, reject) => {
if (this.state === 'fulfilled') {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === 'rejected') {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === 'pending') {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
});
};
});
return promise2;
}
catch(fn){
return this.then(null,fn);
}
}
function resolvePromise(promise2, x, resolve, reject){
if(x === promise2){
return reject(new TypeError('Chaining cycle detected for promise'));
}
let called;
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then;
if (typeof then === 'function') {
then.call(x, y => {
if(called)return;
called = true;
resolvePromise(promise2, y, resolve, reject);
}, err => {
if(called)return;
called = true;
reject(err);
})
} else {
resolve(x);
}
} catch (e) {
if(called)return;
called = true;
reject(e);
}
} else {
resolve(x);
}
}
//resolve方法
Promise.resolve = function(val){
return new Promise((resolve,reject)=>{
resolve(val)
});
}
//reject方法
Promise.reject = function(val){
return new Promise((resolve,reject)=>{
reject(val)
});
}
//race方法
Promise.race = function(promises){
return new Promise((resolve,reject)=>{
for(let i=0;i<promises.length;i++){
promises[i].then(resolve,reject)
};
})
}
//all方法(获取所有的promise,都执行then,把结果放到数组,一起返回)
Promise.all = function(promises){
let arr = [];
let i = 0;
function processData(index,data){
arr[index] = data;
i++;
if(i == promises.length){
resolve(arr);
};
};
return new Promise((resolve,reject)=>{
for(let i=0;i<promises.length;i++){
promises[i].then(data=>{
processData(i,data);
},reject);
};
});
}
1、先在后面加上下述代码
2、npm 有一个promises-aplus-tests插件 npm i promises-aplus-tests -g 可以全局安装 mac用户最前面加上sudo
3、命令行 promises-aplus-tests [js文件名] 即可验证
// 目前是通过他测试 他会测试一个对象
// 语法糖
Promise.defer = Promise.deferred = function () {
let dfd = {}
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
module.exports = Promise;
//npm install promises-aplus-tests 用来测试自己的promise 符不符合promisesA+规范