promise

112 阅读5分钟

异步编程

提到promise,就不得不提异步编程,那什么是异步编程呢?

  • 大家都知道JS是单线程,如果代码同步执行,必然会引起阻塞。如果代码异步执行的话,就不必等待当前代码返回结果,再去执行之后的代码逻辑,能够大大提高资源利用率。
  • 异步编程经历了几个阶段,由回调函数->promise->generator和yield->async和await。

image.png

异步编程各个阶段的优缺点

  • 回调函数会引起回调地狱,多层嵌套代码不易被理解,而且无法处理错误。
  • promise解决了回调地狱问题,可以进行错误处理,但链式调用会造成语义不明确,而且在promise内部无法加断点调试。
  • generator迭代器和yield生成器,同步了代码的书写,在函数执行时,将代码的执行权转移出去,在函数外部将代码的执行权转移回来。
  • async和await是es7提出来的,await它是generator和promise的语法糖,改进了生成器的缺点,在不阻塞线程的情况下,同步代码可以实现异步代码编程,async用来声明是一个异步函数,返回一个promise,await可以暂停后续嗲吗的执行,等待promise执行,await可以等待promise的结果,也可以等待一个表达式。

promise的概念

  • promise是异步编程解决方案,它是一个容器,里面保存着未来才会结束的事件的结果,它接受一个函数作为参数,返回一个promise实例,新建一个promise,构造函数内部立即执行,状态改变后不可更改。
  • 它有三种状态pending(待定)、fulfilled(完成)、reject(拒绝)。
  • 优点:有错误处理机制、避免回调地狱、状态一旦更改,不会再发生变化。
  • 缺点:错误处理机制,不设置回调函数,无法暴露在外部。无法得知进度变化,在pending状态时,不知道下一个阶段。构造函数立即执行,无法取消。

promise的方法

新建一个promise

//通常使用new Promise新建promise,还可以使用Promise.resolve()和Promise.reject()来新建一个promise,下面是结合resolve和reject
function testPromise(value){
	return new Promise((resolve,reject) => {
		if(value){
			resolve(' hello');
		}else{
			reject('no thanks');
		}
	})
}
testPromise(true).then(res => {
	console.log(res);
},(error)=>{
	console.log(error);
})

then()

  • promise.then(),接收两个回调函数作为参数,第一个参数Promise的状态变成resolve时调用,第二个参数是Promise的状态变成rejected时调用,then方法返回的是一个promise实例,因此可以链式调用。
let readFilename = (filename) => {
	fs.readFilename((filename),(err,data) => {
		if(data){
			resolve(data);
		}else{
			reject(err);
		}
	})
}
readFilename('a.json').then((data) => {
	return readFilename('b.json');
}).then((data) => {
	return readFilename('c.json');
})

catch()

  • promise.catch方法相当于then的第二个参数,可以捕获异常,不会停止运行。
Promise.then((res)=>{
	console.log(res);
},err => {
	reject(err);
})

all()

  • promise.all方法,接收一个数组作为参数,如果数组中的全部状态变成resolved,则状态变为resolved,如果一个状态变为rejetched,则状态变为rejected。
let promise1 = new Promise((resolve,rejected) => {
	setTimeout(() => {
		resolve(1);
	},1000);
})
let promise2 = new Promise((resolve,rejected) => {
	setTimeout(() => {
		resolve(2);
	},2000);
})
let promise3 = new Promise((resolve,rejected) => {
	setTimeout(() => {
		resolve(3);
	},3000);
})

Promise.all([promise1,promise2,promise3]).then(res => {
	console.log(res); //[1,2,3]
})

race()

  • promise.race方法,接收一个数组作为参数,返回第一个状态改变的结果,可以用于当执行一个任务,超过多长时间就不做了。
let promise1 = new Promise((resolve,rejected) => {
	setTimeout(() => {
		resolve(1);
	},1000);
})
let promise2 = new Promise((resolve,rejected) => {
	setTimeout(() => {
		resolve(2);
	},2000);
})
let promise3 = new Promise((resolve,rejected) => {
	setTimeout(() => {
		resolve(3);
	},3000);
})

Promise.race([promise1,promise2,promise3]).then(res => {
	console.log(res); //1
},err => {
        console.log(err);
})

allSettled()

  • 语法同all相似,但不同的是,allSettled会返回数组中每一项的结果,不管是不是resolved。
const resolved = Promise.resolve(2);
const rejected = Promise.reject(-1);
const allSettledPromise = Promise.allSettled([resolved, rejected]);
allSettledPromise.then(function (results) {
  console.log(results);
}); // 返回结果: // [ // { status: 'fulfilled', value: 2 }, // { status: 'rejected', reason: -1 } // ]

any()

  • promise.any,参数中如果一个promise变成fulfilled状态,就返回fulfilled状态,如果所有参数变成rejected状态,实例返回rejected状态的结果。
const resolved = Promise.resolve(2);
const rejected = Promise.reject(-1);
const allSettledPromise = Promise.any([resolved, rejected]);
allSettledPromise.then(function (results) {
  console.log(results);
}); // 返回结果:2

finally()

  • 是then的一个特例,无论是否是fulfilled,都会执行finally方法。
promise
.finally(() => {
  // 语句
});

// 等同于
promise
.then(
  result => {
    // 语句
    return result;
  },
  error => {
    // 语句
    throw error;
  }
);

promise如何解决回调地狱的

  • 回调函数延迟绑定
  • 返回值穿透
  • 错误冒泡

如何实现一个promise.all

function promiseAll(promises){
	return new Promise(function(resolve,reject){
		if(!Array.isArray(promises)){
			throw new TypeError('传入的promises应为数组');
		}
		let resolvedNum = 0;
		let promisesLen = promises.length;
		let resolvedRes = [];
		for(let i = 0; i <= promisesLen - 1; i++){
			Promise.resolve(promises[i]).then(value => {
				resolvedNum++;
				resolvedRes[i] = value;
				if(resolvedNum === promisesLen){
					return resolve(resolvedRes);
				}
			},error => {
			  return reject(error);
			})
		}

	})
}


如何实现一个promise


var PENDING = 'pending';
var RESOLVED = 'resolved';
var REJECTED = 'rejected';

function myPromise(fn){
	var self = this;
	this.state = PENDING;
	this.value = null;
	this.resolvedCallbacks = [];
	this.rejectedCallbacks = [];
	//状态变为resolve的方法
	function resolve(value){
		//判断是不是myPromise类型,是的话,等到前一个状态变更后再进行改变
		if(value instanceof myPromise){
			value.then(resolve,reject);
		}
		setTimeout(() => {
			////保证代码的执行顺序为本轮事件循环的末尾
			if(this.state === PENDING){
				self.state = RESOLVED;
				self.value = value;
				self.resolvedCallbacks.forEach(cb=>{
					cb(value);
				})
			}
			
		}, 0);
	}
	//状态变为reject的方法
	function reject(value){
		//保证代码的执行顺序为本轮事件循环的末尾
		setTimeout(() => {
			if(this.state === PENDING){
				self.value = value;
				self.state = REJECTED;
				self.rejectedCallbacks.forEach(cb =>{
					cb(value);
				})
			}
			
		}, 0);
	}

	try{
		//执行相应的函数
		fn(resolve,reject);
	}catch(e){
		reject(e)
	}
	myPromise.prototype.then = function(onResolve,onReject){
		onResolve = typeof onResolve === 'function' ? onResolve : function(value){
			return value;
		};
		onReject = typeof onReject === 'function' ? onReject : function(error){
			throw error;
		}
		//如果当前是pending状态
		if(this.state === PENDING){
			this.resolvedCallbacks.push(onResolve);
			this.rejectCallbacks.push(onReject);
		}
		if(this.state === ReSOLVED){
			onResolve(this.value);
		}
		if(this.state === REJECTED){
			onReject(this.value);
		}
	}
}

var PENDING = 'pending';
var RESOLVED = 'resolved';
var REJECTED = 'rejected';
function myPromise(fn){
	var self = this;
	this.state = PENDING;
	this.value = null;
	this.resolvedCallbacks = [];
	this.rejectedCallbacks = [];
	//状态变为resolve
	function resolve(value){
		if(value instanceof myPromise){
			value.then(resolve,reject);
		}
		if(self.state === PENDING){
			setTimeout(() => {
				self.state = RESOLVED;
				self.value = value;
				//执行回调函数
				self.resolvedCallbacks.forEach(cb=> cb(value));
				
			}, 0);
		}
	}
	function reject(value){
		if(self.state === PENDING){
			setTimeout(() => {
				self.state = REJECTED;
				self.value = value;
				//执行回调函数
				self.rejectedCallbacks.forEach(cb=>{
					cb(value);
				})
				
			}, 0);
		}
	}
	try{
		fn(resolve,reject);
	}catch(e){
		reject(e);
	}
	myPromise.prototype.then = function(onResolve,onReject){
		onResolve = typeof onResolve === 'function' ? onResolve : function(value){
			return value;
		}
		onReject = typeof onReject === 'function' ? onReject : function(err){
			throw err;
		}
		if(this.state === PENDING) {
			this.resolvedCallbacks.push(onResolve);
			this.rejectedCallbacks.push(onReject);
		}
		if(this.state === RESOLVED){
			onResolve(this.value);
		}
		if(this.state === REJECTED){
			onReject(this.value);
		}
	}
}

如何实现一个promise.race

function promiseRace(args){
	return new Promise(function(resolve,reject){
		for(let i = 0; i <= args.length - 1; i++){
			args.then(resolve,reject);
		}
	})
}