异步编程
提到promise,就不得不提异步编程,那什么是异步编程呢?
- 大家都知道JS是单线程,如果代码同步执行,必然会引起阻塞。如果代码异步执行的话,就不必等待当前代码返回结果,再去执行之后的代码逻辑,能够大大提高资源利用率。
- 异步编程经历了几个阶段,由回调函数->promise->generator和yield->async和await。
异步编程各个阶段的优缺点
- 回调函数会引起回调地狱,多层嵌套代码不易被理解,而且无法处理错误。
- 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);
}
})
}