预备知识
- 回调函数
- 高级函数
- 发布-订阅模式
- promise A+ 规范
promise是什么,能干什么
Promise是异步编程的一种解决方案,它可以解决异步回调地狱的问题,防止层层嵌套对程序代码带来的难维护性。既然带来了方便,我们就有必要学习它的原理以及底层实现,所以笔者就按照PromiseA+规范写了一个简单的Promise,并实现了Promise.all(),Promise.race()等API
- 解决回调地狱
- 解决多个回调函数同步结果
promise的几个方法
- promise.all()
- promise.race()
- promise.resolve()
- promise.reject()
promise的三种状态
- 等待态 pending
- 成功态 resolved
- 失败态 rejected
promise的特点
- 1.executor 默认时new的时候就自动执行
- 2.每个promise的实例 都有then方法
- 3.then方法中有两个参数 分别是成功的回调和失败的回调
- 4.then方法是异步的(微任务) // 微任务先于宏任务执行
- 5.同一个promise的实例可以then多次,成功时回调用所有的成功方法,失败时会调用所有的失败方法
- 6.new Promise中可以支持异步行为
- 7.如果发现错误就会走入失败态
下一次的输入需要上一次的输出 (有依赖关系)
- 1.如果一个promise执行完后 返回的还是一个promise,会把这个promise 的执行结果,传递给下一次then中
- 2.如果then中返回的不是promise 是一个普通值,会将这个普通值作为下次then的成功的结果
- 3.如果当前then中失败了 会走下一个then的失败
- 4.如果返回的是undefined 不管当前是成功还是失败 都会走下一次的成功
- 5.catch是错误没有处理的情况下才会走
- 6.then中可以不写东西,相当于白写 (值的穿透)
promise A+ 规范
- 原文
- 翻译
- 校验插件
npm install promises-aplus-tests -g
用于检查自己写的promise是否符合promise规范
简单实现 待完善
function Promise(executor){
let self = this;
self.value = undefined; // 成功时的参数
self.reason = undefined; // 失败时的参数
self.status = 'pending'; // 状态
self.onResolvedCallbacks = [];// 存放then中成功的回调
self.onRejectedCallbacks = []; // 存放then中失败的回调
function resolve(value){ //
if(self.status === 'pending'){
self.value = value;
self.status = 'resolved';
self.onResolvedCallbacks.forEach(fn=>fn());
}
}
function reject(reason){
if(self.status === 'pending'){
self.reason = reason;
self.status = 'rejected';
self.onRejectedCallbacks.forEach(fn=>fn());
}
}
// 如果函数执行时发生异常 就走到失败中
try{
executor(resolve,reject);
}catch(e){
reject(e);
}
}
Promise.prototype.then = function(onFulfilled,onRejected){
let self = this;
if(self.status === 'resolved'){
onFulfilled(self.value);
}
if(self.status === 'rejected'){
onRejected(self.reason);
}
if(self.status === 'pending'){
// 保存回调函数
self.onResolvedCallbacks.push(()=>{
onFulfilled(self.value);
});
self.onRejectedCallbacks.push(()=>{
onRejected(self.reason)
});
}
}
module.exports = Promise;
复制代码
基本实现
function Promise(executor) {
let self = this;
self.value = undefined; // 成功的值
self.reason = undefined; // 失败的原因
self.status = 'pending'; // 值是pending状态
self.onResolvedCallbacks = []; // 可能new Promise的时候会有异步操作,保存成功和失败的回调
self.onRejectedCallbacks = [];
function resolve(value) { // 把状态改成成功态
if (self.status === 'pending') { // 只有等待态 可以改变状态
self.value = value;
self.status = 'resolved';
self.onResolvedCallbacks.forEach(fn => fn());
}
}
function reject(reason) { // 把状态改成失败态
if (self.status === 'pending') {
self.reason = reason;
self.status = 'rejected';
self.onRejectedCallbacks.forEach(fn => fn());
}
}
try {
// 默认new Promise时 应该执行对应的执行器(同步执行)
executor(resolve, reject);
} catch (e) { // 如果执行exectuor时 发生错误 就会让当前的promise变成失败态
reject(e);
}
}
/**
*
* @param {*} promise2 then的返回值 (返回的新的promise)
* @param {*} x then中成功或者失败函数的返回值
* @param {*} resolve promise2的resolve
* @param {*} reject promise2的reject
*/
// 所有的promise都遵循这个规范 (所有的promise可以通用)
function resolvePromise(promise2,x,resolve,reject){
// promise2和函数执行后返回的结果是同一个对象
if(promise2 === x){
return reject(new TypeError('Chaining cycle'));
}
let called;
// x可能是一个promise 或者是一个普通值
if(x!==null && (typeof x=== 'object' || typeof x === 'function')){
try{
let then = x.then; // 取对象上的属性 怎么能报异常呢?(这个promise不一定是自己写的 可能是别人写的 有的人会乱写)
// x可能还是一个promise 那么就让这个promise执行即可
// {then:{}}
// 这里的逻辑不单单是自己的 还有别人的 别人的promise 可能既会调用成功 也会调用失败
if(typeof then === 'function'){
then.call(x,y=>{ // 返回promise后的成功结果
// 递归直到解析成普通值为止
if(called) return; // 防止多次调用
called = true;
// 递归 可能成功后的结果是一个promise 那就要循环的去解析
resolvePromise(promise2,y,resolve,reject);
},err=>{ // promise的失败结果
if(called) return;
called = true;
reject(err);
});
}else{
resolve(x);
}
}catch(e){
if(called) return;
called = true;
reject(e);
}
}else{ // 如果x是一个常量
resolve(x);
}
}
// then调用的时候 都是异步调用 (原生的then的成功或者失败 是一个微任务)
Promise.prototype.then = function (onFulfilled, onRejected) {
// 成功和失败的回调 是可选参数
// onFulfilled成功的回调 onRejected失败的回调
let self = this;
let promise2;
// 需要没次调用then时都返回一个新的promise
promise2 = new Promise((resolve, reject) => {
if (self.status === 'resolved') {
setTimeout(()=>{
try {
// 当执行成功回调的时候 可能会出现异常,那就用这个异常作为promise2的错误的结果
let x = onFulfilled(self.value);
//执行完当前成功回调后返回结果可能是promise
resolvePromise(promise2,x,resolve,reject);
} catch (e) {
reject(e);
}
},0)
}
if (self.status === 'rejected') {
setTimeout(()=>{
try {
let x = onRejected(self.reason);
resolvePromise(promise2,x,resolve,reject);
} catch (e) {
reject(e);
}
},0)
}
if (self.status === 'pending') {
self.onResolvedCallbacks.push(() => {
setTimeout(()=>{
try {
let x = onFulfilled(self.value);
resolvePromise(promise2,x,resolve,reject);
} catch (e) {
reject(e);
}
},0)
});
self.onRejectedCallbacks.push(() => {
setTimeout(()=>{
try {
let x = onRejected(self.reason);
resolvePromise(promise2,x,resolve,reject);
} catch (e) {
reject(e);
}
},0)
});
}
});
return promise2
}
// 为什么加setTimeout (规范要求的)
Promise.defer = Promise.deferred = function(){
let dfd = {};
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
})
return dfd;
}
module.exports = Promise;
复制代码
最终版本
function Promise(executor) {
let self = this;
self.value = undefined;
self.reason = undefined;
self.status = 'pending';
self.onResolvedCallbacks = [];
self.onRejectedCallbacks = [];
function resolve(value) {
if (self.status === 'pending') {
self.value = value;
self.status = 'resolved';
self.onResolvedCallbacks.forEach(fn => fn());
}
}
function reject(reason) {
if (self.status === 'pending') {
self.reason = reason;
self.status = 'rejected';
self.onRejectedCallbacks.forEach(fn => fn());
}
}
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
function resolvePromise(promise2,x,resolve,reject){
if(promise2 === x){
return reject(new TypeError('Chaining cycle'));
}
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{ // 如果x是一个常量
resolve(x);
}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function'?onFulfilled:val=>val;
onRejected = typeof onRejected === 'function'?onRejected: err=>{throw err}
let self = this;
let promise2;
promise2 = new Promise((resolve, reject) => {
if (self.status === 'resolved') {
setTimeout(()=>{
try {
let x = onFulfilled(self.value);
resolvePromise(promise2,x,resolve,reject);
} catch (e) {
reject(e);
}
},0)
}
if (self.status === 'rejected') {
setTimeout(()=>{
try {
let x = onRejected(self.reason);
resolvePromise(promise2,x,resolve,reject);
} catch (e) {
reject(e);
}
},0)
}
if (self.status === 'pending') {
self.onResolvedCallbacks.push(() => {
setTimeout(()=>{
try {
let x = onFulfilled(self.value);
resolvePromise(promise2,x,resolve,reject);
} catch (e) {
reject(e);
}
},0)
});
self.onRejectedCallbacks.push(() => {
setTimeout(()=>{
try {
let x = onRejected(self.reason);
resolvePromise(promise2,x,resolve,reject);
} catch (e) {
reject(e);
}
},0)
});
}
});
return promise2
}
// 语法糖 (甜) 目的是解决promise嵌套问题的 Q.derfer()
Promise.defer = Promise.deferred = function(){
let dfd = {};
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
})
return dfd;
}
// 类上的方法
Promise.reject = function(reason){
return new Promise((resolve,reject)=>{
reject(reason);
})
}
Promise.resolve = function(value){
return new Promise((resolve,reject)=>{
resolve(value);
})
}
Promise.prototype.catch = function(onRejected){
// 默认不写成功
return this.then(null,onRejected);
};
// all方法
Promise.all = function(promises){
return new Promise((resolve,reject)=>{
let arr = [];
let i = 0;
function processData(index,data){
arr[index] = data;
if(++i == promises.length){
resolve(arr);
}
}
for(let i = 0;idata=>{ // data是成功的结果
processData(i,data);
},reject);
}
})
}
// 以请求最快的为准
Promise.race = function(promises){
return new Promise((resolve,reject)=>{
for(let i = 0;imodule.exports = Promise;
复制代码