Promise 简单介绍与使用

异步编程新的解决方案

  • fs 文件操作
  • 数据库操作
  • AJAX
  • 定时器

Promise 的优势

  • 支持链式调用
  • 便于异常处理
  • 指定毁掉

Promise 的简单使用

const p = new Promise((resolve, reject)=>{ // resolve 和 reject 都是函数类型,当任务执行成功是, resolve (解决)就会被调用,当任务执行失败时就会执行 reject (拒绝)
	setTimeout(()=>{
		if (业务判断是否成功){
			resolve() // 调用这个,会将 Promise 对象的状态设置为成功。可以给该函数任意传参,到时候then中的回调就会接收到该参数
		}else{
			reject() // 调用这个,会将 Promise 对象的状态设置为失败。可以给该函数任意传参,到时候then中的回调就会接收到该参数
		}
	})
})

// then 接收2个参数,第一个参数是接收成功时候的回调,第二个是接收失败时候的回调
p.then(()=>{
// 当上面的 resolve() 被调用时,这里的代码就会执行。如果上面调用 resolve()时传了参数,这里就可以获取到该参数
},()=>{
// 当上面的 reject() 被调用时,这里的代码就会执行。如果上面调用 reject()时传了参数,这里就可以获取到该参数
})

使用 Promise 封装 AJAX

# 方法1
function ajax(url, data = {}, type = "GET") {
	return new Promise((resolve, reject) => {
		$.ajax({
			type: type,
			url: url,
			data: data,
			dataType: "json",
			success: function(data) {
				resolve(data);
			},
			error: function(err) {
				reject(err);
			}
		})
	})
}

let url = "http://localhost:5000/login";
let data = {
	username: "admin",
	password: "admin"
}

let promise = ajax(url, data, "GET"); //注意这里返回的是promise对象
promise.then(data = > { //f1为第一个回调处理函数
	f1(data);
}).then(data2 = > { //f2为第二个回调处理函数
	f2(data2);
}).catch (err = > {
	console.log(err);
})



# 方法2
function ajax(url, data = {}, requestType = "GET") {
    return new Promise(function(resolve, reject) {
        const xhr = new XMLHttpRequest();
        xhr.open(requestType, url); // 定义请求方式
        xhr.responseType = 'json'; // 定义返回值类型
        xhr.onload = function() {
            if(this.status === 200) {
                resolve(this.response);
            } else {
                reject(new Error(this.statusText));
            }
        }
        // 或以下这段也行
        // xhr.onreadystatechange = function() {
        // 	if (xhr.readyState===4){
        // 		if(xhr.status >=200 && xhr.status <300){
        // 			resolve(xhr.response);
        // 		}else{
        // 			reject(xhr.status);
        // 		}
        // 	}
        // }
        xhr.send(data); // 如果没数据就可以不用传参
    })
}

ajax('/api/xxx.json').then((value)=> { // value 就是自定义的形参名,可以写成任意字符
    console.log(value);
    return ajax('api/yyy.json');
}, (error)=> { // error 就是自定义的形参名,可以写成任意字符,他能捕获调用ajax('/api/xxx.json')时的异常,但不能捕获ajax('api/yyy.json')调用时的异常,而catch可以
    console.log(error);
}).catch(function(error) {  // 更像是给整个promise链条注册的失败回调,建议都是用这种情况,更方便,也更符合链式调用特性
    console.log(error);
})

Promise 的状态

Promise 的实例对象中有一个属性 PromiseState ,它有3个值

  • pending: 未决定的
  • resolve/fullfilled: 成功
  • reject: 失败

Promise 对象的值

Promise 的实例对象中有一个属性 PromiseResult 保存着该 Promise 对象成功或失败的结果

Promise API

Promise 的构造函数

Promise 的构造函数 Promise(executor){}

  • executor 函数: 执行器 (resolve, reject)={},executor会在 Promise 内部立即同步调用,异步操作在执行器中执行。也就是 (resolve, reject)=

all()

在多个 Promise 执行成功后,这个 Promise 对象才变为成功状态

let p1 = new Promise((resolve,reject)=>{
	resolve("OK")
})
let p1 = Promise.resolve("success")
let p2 = Promise.resolve("success2")

const result = Promise.all([p1,p2,p3]);
console.log(result); // 因为上面的3个 Promise 都调用了 resolve,所以输出的 promise 对象的状态是 fullfilled,PromiseResult 保存着上面的执行成功的结果 ["OK","success","success2"]

// 如果其中一个 Promise 调用的是 reject("error111") ,则 result 的 PromiseResult 就是 "error111"

race()

在多个 Promise 执行时,第一个执行完成的 promise 的结果就是最终结果

let p1 = new Promise((resolve,reject)=>{
	resolve("OK")
})
let p1 = Promise.resolve("success")
let p2 = Promise.resolve("success2")

const result = Promise.race([p1,p2,p3]);
console.log(result); // 因为上面的3个 Promise 那个先执行 resolve 或 reject ,所以输出的 result 对象的状态就是这个结果

Promise 关键问题

修改 Promise 状态

let p1 = new Promise((resolve,reject)=>{
	// resolve("OK") 方法1
	// reject("OK") 方法2
	// throw '出问题了' 方法3
})

在 then() 中修改 Promise 状态

let p1 = new Promise((resolve,reject)=>{
	// resolve("OK") 方法1
	// reject("OK") 方法2
	// throw '出问题了' 方法3
})

let result = p1.then(value=>{
	// 如果抛出错误,那么 result 对象的结果就是失败
	// throw '出了问题'

	// 如果返回结果是非 Promise 对象,则 result 对象的结果就是成功,它的结果就是返回的数据
	// return 123

	// 如果返回结果是 Promise 对象,那么 result 对象的结果和值取决于返回的这个 Promise 对象的结果和值
	// return new Promise((resolve,reject)=>{
		// resolve("OK")
	// })
})

多个 Promise 任务串联执行

let p = new Promise((resolve,reject)=>{
	setTimeout(()=>{
		resolve("OK");
	},1000)
})

p.then(value=>{
	return new Promise((resolve,reject)=>{
		resolve("success")
	})
}).then(value=>{
	console.log(value)
}).then(value=>{
	console.log(value)
})


// 执行结果输出的是"success"  undefined,因为第一个 Promise 使用了 setTimeout,所以在执行第一个 then 时 new Promise 的结果已经将其覆盖了,所以第二个 then 的 value 就是第一个 then return 的 Promise 的结果,又因为第二个 then 没有返回任何值,所以第三个 then 的 value 就是 undefined

Promise 异常穿透

let p = new Promise((resolve,reject)=>{
	setTimeout(()=>{
		resolve("OK");
	},1000)
})

p.then(value=>{
	throw '失败啦'
}).then(value=>{
	console.log(222)
}).then(value=>{
	console.log(333)
}).catch(reason=>{
	console.warn(reason)
})


// 执行结果输出的是'失败啦',而不会输出 222、333

中断 Promise 调用链

let p = new Promise((resolve,reject)=>{
	setTimeout(()=>{
		resolve("OK");
	},1000)
})

p.then(value=>{
	console.log(111)
}).then(value=>{
	console.log(222)
	return new Promise((resolve,reject)=>{}) # 调用一个空的即可中断之后的 then 的执行。且只有这一个方式可以正常中断调用链
}).then(value=>{
	console.log(333)
}).catch(reason=>{
	console.warn(reason)
})

// 输出 111、222

Promise 自定义封装

自己简单实现 Promise

原理理解版:

function Promise(executor){
	// 添加属性
	this.PromiseState = 'pending';
	this.PromiseResult = null;
	this.callbacks = [];

	const self = this;

	// resolve 函数
	function resolve(data){
		if (self.PromiseState !== 'pending') return; // 要保证状态只能被改一次
		this.PromiseState = 'fullfilled';
		this.PromiseResult = data;

		setTimeout(()=>{
			self.callbacks.forEach(item=>{
			item.onResolved(data);
		})
		});
	}

	// reject 函数
	function reject(data){
		if (self.PromiseState !== 'pending') return;// 要保证状态只能被改一次
		this.PromiseState = 'rejected';
		this.PromiseResult = data;
		setTimeout(()=>{
			self.callbacks.forEach(item=>{
			item.onRejected(data);
		})
		});
	}

	try{
		// 同步调用执行器函数 executor
		executor(resolve, reject)
	}catch(e){
		reject(e) // throw "报错内容",的"报错内容"就会传给 e,然后 e 再传给 reject
	}
}


// 添加 then 方法
Promise.prototype.then = function(onResolved,onRejected){
	const self = this;
	// 判断回调函数参数
	if (typeof onRejected !== 'function'){
		onRejected = reason=>{
			throw reason;
		}
	}

	if (typeof onResolved !== 'function'){
		onResolved = value=>value;
		// onResolved = value=>{return value}; // 等同于上面那句
	}

	return new Promise((resolve, reject)=>{
		// 封装函数
		function callback(type){
			try{
				// 获取函数的执行结果
				let result = type(self.PromiseResult);
				if (result instanceof Promise){
					result.then(v=>{
						resolve(v);
					},r=>{
						resolve(r);
					})
				}else{
					// 结果的对象状态为成功
					resolve(result);
				}
			}catch(e){
				reject(e);
			}
		}

		if(this.PromiseState === 'fullfilled'){
			setTimeout(()=>{
				callback(onResolved);
			})
		}
		if(this.PromiseState === 'rejected'){
			setTimeout(()=>{
				callback(onRejected);
			})
			
		}
		if(this.PromiseState === 'pending'){
			// 保存回调函数
			this.callbacks.push({onResolved: function(){
					callback(onResolved);
			},onRejected: function(){
					callback(onRejected);
			}});
		}
	})
}


// 添加 catch 方法
Promise.prototype.catch = function(onRejected){
	return this.then(undefined, onRejected);
}

// 添加 resolve 方法
Promise.resolve = function(value){
	// 返回 promise 对象
	return new Promise((resolve,reject)=>{
		if (value instanceof Promise){
			value.then(v=>{
				resolve(v);
			},r=>{
				reject(r);
			})
		}else{
			resolve(value);
		}
	});
}

// 添加 rejected 方法
Promise.rejected = function(reason){
	// 返回 promise 对象
	return new Promise((resolve,reject)=>{
		reject(reason);
	});
}

// 添加 all 方法
Promise.all = function(promise){
	// 返回结果为 promise 对象
	return new Promise((resolve,reject)=>{
		let count = 0;
		let arr = []; // 准备个数组存放所有 promise 的执行结果
		for(let i=0;i<promise.length;i++){
			promise[i].then(v=>{
				// 得知所有对象状态是成功的,才调用resolve
				count++;
				arr[i] = v;
				if (count === promise.length){
					resolve(arr);
				}
			},r=>{
				reject(r);
			},)
		}
	});
}


// 添加 race 方法
Promise.race = function(promise){
	// 返回结果为 promise 对象
	return new Promise((resolve,reject)=>{
		for(let i=0;i<promise.length;i++){
			promise[i].then(v=>{
				resolve(v);
			},r=>{
				reject(r);
			},)
		}
	});
}

class 版

class Promise{
	// 构造方法
	constructor(executor){
		// 添加属性
		this.PromiseState = 'pending';
		this.PromiseResult = null;
		this.callbacks = [];

		const self = this;

		// resolve 函数
		function resolve(data){
			if (self.PromiseState !== 'pending') return; // 要保证状态只能被改一次
			this.PromiseState = 'fullfilled';
			this.PromiseResult = data;

			setTimeout(()=>{
				self.callbacks.forEach(item=>{
				item.onResolved(data);
			})
			});
		}

		// reject 函数
		function reject(data){
			if (self.PromiseState !== 'pending') return;// 要保证状态只能被改一次
			this.PromiseState = 'rejected';
			this.PromiseResult = data;
			setTimeout(()=>{
				self.callbacks.forEach(item=>{
				item.onRejected(data);
			})
			});
		}

		try{
			// 同步调用执行器函数 executor
			executor(resolve, reject)
		}catch(e){
			reject(e) // throw "报错内容",的"报错内容"就会传给 e,然后 e 再传给 reject
		}
	}


	// then 方法封装
	then(onResolved,onRejected){
		const self = this;
		// 判断回调函数参数
		if (typeof onRejected !== 'function'){
			onRejected = reason=>{
				throw reason;
			}
		}

		if (typeof onResolved !== 'function'){
			onResolved = value=>value;
			// onResolved = value=>{return value}; // 等同于上面那句
		}

		return new Promise((resolve, reject)=>{
			// 封装函数
			function callback(type){
				try{
					// 获取函数的执行结果
					let result = type(self.PromiseResult);
					if (result instanceof Promise){
						result.then(v=>{
							resolve(v);
						},r=>{
							resolve(r);
						})
					}else{
						// 结果的对象状态为成功
						resolve(result);
					}
				}catch(e){
					reject(e);
				}
			}

			if(this.PromiseState === 'fullfilled'){
				setTimeout(()=>{
					callback(onResolved);
				})
			}
			if(this.PromiseState === 'rejected'){
				setTimeout(()=>{
					callback(onRejected);
				})
				
			}
			if(this.PromiseState === 'pending'){
				// 保存回调函数
				this.callbacks.push({onResolved: function(){
						callback(onResolved);
				},onRejected: function(){
						callback(onRejected);
				}});
			}
		})
	}

	catch(onRejected){
		return this.then(undefined, onRejected);
	}

	// 属于类,而不属于实例对象
	static resolve(value){
	// 返回 promise 对象
		return new Promise((resolve,reject)=>{
			if (value instanceof Promise){
				value.then(v=>{
					resolve(v);
				},r=>{
					reject(r);
				})
			}else{
				resolve(value);
			}
		});
	}

	// 添加 rejected 方法
	static rejected(reason){
		// 返回 promise 对象
		return new Promise((resolve,reject)=>{
			reject(reason);
		});
	}

	// 添加 all 方法
	static all(promise){
		// 返回结果为 promise 对象
		return new Promise((resolve,reject)=>{
			let count = 0;
			let arr = []; // 准备个数组存放所有 promise 的执行结果
			for(let i=0;i<promise.length;i++){
				promise[i].then(v=>{
					// 得知所有对象状态是成功的,才调用resolve
					count++;
					arr[i] = v;
					if (count === promise.length){
						resolve(arr);
					}
				},r=>{
					reject(r);
				},)
			}
		});
	}


	// 添加 race 方法
	static race(promise){
		// 返回结果为 promise 对象
		return new Promise((resolve,reject)=>{
			for(let i=0;i<promise.length;i++){
				promise[i].then(v=>{
					resolve(v);
				},r=>{
					reject(r);
				},)
			}
		});
	}
}

async 与 await

async 函数

  • 函数的返回值为 promise 对象
  • promise 对象的结果由 async 函数执行的返回值决定,如果 async 函数返回的是一个 promise 对象,那么 async 的结果的 promise 对象就是 async 函数中返回的 promise 结果和状态
async function main(){

}

let result = main();
console.log(result); // 输出发现是个 promise 对象

await 表达式

  • await 右侧的表达式一般为 promise 对象,但也可以是其他值,比如数字、字符串等
  • 如果表达式是 promise 对象,await 返回的是 promise 成功的值
  • 如果表达式是其他值,则将此值作为 await 的返回值
async function main(){
	// 1. 右侧为 promise 的情况
	let p = new Promise((resolve,reject)=>{
		resolve("OK");
	})

	let res = await p; // 会返回 promise 成功的值,也就是 OK
	console.log(res);

	// 2. 右侧为其他数据的情况
	let res2 = await 20; // await 右侧是其他值时,是什么值就返回什么值
	console.log(res2);


	// 3. 右侧为 promise 失败的情况
	let p3 = new Promise((resolve,reject)=>{
		reject("error, error");
	})
	try{
		let res3 = await p3; // 就会抛出一个错误,需要使用 try...catch 捕获
		console.log(res3);
	}catch(e){
		console.warn(e);
	}
}

async 与 await 需要注意的地方

  • await 必须写在 async 函数中,但 async 中可以没有 await
  • 如果 await 的 promise 失败了,就会抛出异常,需要通过 try…catch 捕获处理

async 与 await 结合使用

// 比如要读取 1.html、2.html、3.html 这3个文件

// 传统写法
const fs = require('fs');
fs.readFile('./resource/1.html',(err,data1)={
	if(err) throw err;
	fs.readFile('./resource/2.html',(err,data2)={
		if(err) throw err;
		fs.readFile('./resource/3.html',(err,data3)={
			if(err) throw err;
			console.log(data1+data2+data3);
		})
	})
})


const util = require('util');
const mineReadFile = util.promisify(fs.readFile); // promisify 方法,可以将传进去的API转变成 promise 形式的函数

// 使用 async 与 await 方式
async function main()
{
	try{
		// 读取第一个文件内容
		let data1 = await mineReadFile('./resource/1.html')
		let data2 = await mineReadFile('./resource/2.html')
		let data3 = await mineReadFile('./resource/3.html')
		console.log(data1+data2+data3);
	}catch(e){
		console.log(e)
	}
}

Q.E.D.


做一个热爱生活的人