异步编程与Promise

45 阅读4分钟

异步编程

JavaScript是基于单线程的事件循环机制构建的,单线程意味着在任何时候只有一个主线程来处理所有任务。

当有异步任务要处理时,主线程会挂起该任务,异步任务处理完成,JavaScript会将该任务加入到一个事件队列中,被放入事件队列的任务回调不会立即执行,而是等当前执行栈中的所有任务执行完毕再去执行。

异步任务有两种类型,微任务和宏任务,每种类型都有自己对应的任务队列。

当执行栈中所有任务执行完毕,会去检查微任务队列是否有事件,如果有,则依次执行完微任务队列所有的事件对应的回调,然后再去宏任务队列取出一个事件,把对应的回调加入到当前执行栈,开始执行,当执行栈所有的任务都执行完毕,检查微任务队列是否有事件存在。

一直重复此过程,这个循环就是事件循环

Promise

在Promise之前通常采用回调模式,回调模式多个方法嵌套会有回调地狱问题。

Promise不会立即开始执行,而是先返回一个表示异步读取操作的Promise对象,未来对这个对象的操作完全取决于Promise的生命周期。

Promise的生命周期:

pending 进行中、fulfilled 异步操作成功完成、rejected 异步操作失败。

当Promise状态改变时,通过then方式采取特定的行动,then方法有两个参数

第一个是当Promise状态变为fulfilled时要调用的函数,第二个是当Promise状态变为rejected时要调用的函数。

let fs = require("fs");
function getData() {
	return new Promise((resolve, reject) = >{
		fs.readFile('./test.js', 'utf8', (err, data) = >{
			if (err) {
				reject(err)
			} else {
				resolve(data)
			}
		})
	})
}
let promise = getData();
promise.then(data = >{
	//完成
	console.log(data)
},err = >{
	//拒绝
	console.error(err)
}) 
promise.then(data = >{
	//完成
	console.log(data)
}) 
promise.then(null, err = >{
	//拒绝
	console.error(err)
})
promise.then(null, err = >{
	//拒绝
	console.error(err)
})
//等同于
promise.catch(err = >{
	//拒绝
	console.error(err)
})

创建未完成的Promise

用Promise构造函数可以创建新的Promise,构造函数只接受一个包含初始化Promise代码的执行器函数,执行器接受两个参数,分别是resolve函数和 reject函数,执行器成功时调用resolve,失败时则调用reject函数。

let fs = require("fs");
function getData() {
	return new Promise((resolve, reject) = >{
		fs.readFile('./test.js', 'utf8', (err, data) = >{
			if (err) {
				reject(err)
			} else {
				resolve(data)
			}
		})
	})
}

创建已处理的Promise

let promise = Promise.resolve(1);
promise.then(value = >{
	console.log(value); //1
})
let promise = Promise.reject(1);
promise.catch(value = >{
	console.log(value); //1
})

执行器错误

let promise = new Promise((resolve, reject) = >{
	throw new Error("hh")
}) 
promise.catch(error = >{
	console.log(error.message) //hh
})

串联Promise

每次调用then()方法或者catch()方法,会返回另一个Promise,只有当第一个Promise完成或者被拒绝,第二个才会被调用。

let p1 = new Promise((resolve, reject) = >{
	resolve(1);
}) 
p1.then(value = >{
	console.log(value);
}).then(() = >{
	console.log('哈哈');
})

串联Promise捕获错误

let p1 = new Promise((resolve, reject) = >{
	resolve(1);
}) 
p1.then(value = >{
	console.log(value);
	throw new Error('error');
}).catch((error) = >{
	console.log(error.message); //error
})

串联Promise返回值

let p1 = new Promise((resolve, reject) = >{
	resolve(2)
});
p1.then(value = >{
	console.log(value); //2
	return value + 2;
}).then(value = >{
	console.log(value); //4
})
let p1 = new Promise((resolve, reject) = >{
	reject(2)
});
p1.catch(value = >{
	console.log(value); //2
	return value + 2;
}).then(value = >{
	console.log(value); //4
})

在Promise链中返回Promise

let p1 = new Promise((resolve, reject) = >{
	resolve(2);
}) 
let p2 = new Promise((resolve, reject) = >{
	resolve(4);
}) 
p1.then(value = >{
	console.log(value); //2
	return p2;
}).then(value = >{
	console.log(value); //4
})

Promise.all()

Promise.all()只接收一个数组参数并返回一个Promise,该数组参数里面是多个Promise,只有当数组里面所有Promise状态为已完成时,该返回的Promise状态才会变成已完成

let p1 = new Promise((resolve, reject) = >{
	resolve(1);
}) 
let p2 = new Promise((resolve, reject) = >{
	resolve(2);
}) 
let p3 = new Promise((resolve, reject) = >{
	resolve(3);
}) 
let promise = Promise.all([p1, p2, p3]) 
promise.then(value = >{
	console.log(value); //[1, 2, 3]
})

只要有一个返回拒绝,Promise就会调用catch方法,因为value接收的是值而不是数组,所以只会返回第一个拒绝的value。

let p1 = new Promise((resolve, reject) = >{
	reject(1);
}) 
let p2 = new Promise((resolve, reject) = >{
	reject(2);
}) 
let p3 = new Promise((resolve, reject) = >{
	reject(3);
}) 
let promise = Promise.all([p1, p2, p3]) 
promise.catch(value = >{
	console.log(value); //1
})

Promise.race()

Promise.race()接收的也是一个数组,返回一个Promise,不同的是,这里返回的Promise只会处理数组里面第一个完成状态的Promise,其余的结果会被忽略掉。

let p1 = new Promise((resolve, reject) = >{
	setTimeout(() = >{
		reject(33);
	},0)
}) 
let p2 = new Promise((resolve, reject) = >{
	reject(5);
}) 
let p3 = new Promise((resolve, reject) = >{
	reject(3);
}) 
let promise = Promise.race([p1, p2, p3]) 
promise.then(value = >{
	console.log(value);
}).catch(value = >{
	console.log(value); //5
})

Promise继承

class MyPromise extends Promise {
	success(resolve, reject) {
		return this.then(resolve, reject);
	}
	failure(reject) {
		return this.catch(reject);
	}
}
let p1 = new MyPromise((resolve, reject) = >{
	reject(3);
}) 
p1.success(value = >{
	// console.log(value);
}).catch(value = >{
	console.log(value); //3
})