JavaScrip之异步和同步、promise、async、await


1、promise基础语法

1.1、概念

1、promise是用来管理异步编程的,它本身不是异步的。new promise的时候会立即执行executor函数,只不过会在executor函数中处理一个异步操作。
2、promise有三种状态,分别是:pending(初始状态)、fulfilled(成功状态)和rejected(失败状态)。
3、promise的返回值是用来记录成功的结果或者失败的原因。
4、promise的诞生是为了解决异步请求中的回调地狱问题。
5、promise是一种设计模式,ES6中提供一个JavaScript内置类Promise来实现这种设计模式。
6、new Promise的时候先执行executor函数,在这里开启一个异步操作的任务,此时不等待,把其放入EventQuque任务(微任务)队列中,继续执行then方法,把then方法中的两个函数存储起来,此时还不执行这两个函数。当executor函数中的异步操作结束了,基于resolve/reject控制Promise状态,从而决定执行then存储的函数中的某一个函数。
7、执行resolve或者reject函数,都可以修改promise的状态。一旦状态被改变,再执行resolve或者reject就没用了。
8、resolve或者reject的执行,不论是否放到异步操作中,都需要等待then先执行完,把方法(函数)存储起来,才会在更改状态后执行then中对应的方法。
9、then方法执行结束会返回一个新的Promise实例。new Promise出来的实例,成功或者失败,取决于executor函数执行的时候,执行的是resolve还是reject决定的,再或者executor函数执行发生异常错误,也是会把实例状态改为失败。
10、then中存储的方法执行结果决定状态,上一个then中某个方法执行的结果,决定下一个then中哪一个方法会执行。无论是成功的方法执行,还是失败的方法执行,只要执行抛出异常,都会把实例的状态改为失败。
11、方法中如果返回一个新的Promise实例,返回这个实例的结果是成功或者失败,也决定了当前实例是成功还是失败。剩下的情况基本上都是让实例变为成功状态。
12、方法返回的结果是当前实例的value值,上一个then中的方法返回的结果会传递到下一个then的方法中。
13、then中也可以只写一个或者不写函数,then(fn)/then(null, fn)。遇到一个then,要执行成功或者失败的方法,如果此方法并没有在当前then中被定义,则顺延到下一个对应的函数。
14、Promise.all(array)返回的结果是一个Promise实例,要求array数组中的每一项都是一个新的的Promise实例,Promise.all()是等待所有数组中的实例状态都为成功才会让all实例状态为成功,value是一个集合,存储着数组中每一个实例返回的结果。凡是数组中有一个实例状态为失败,all实例的状态也是失败。
15、Promise.race(array)和all不同的地方,race是赛跑,也就是array数组中不管哪一个先处理完,处理完的结果作为race实例的最终结果。
16、async和await是ES7中Promise操作的语法糖。async是让一个普通函数返回的结果变为status = resolved,并且value = return结构的Promise实例。async最主要的作用是配合await使用,因为一旦在函数中使用await ,那么当前函数必须用async修饰。await会等待当前Promise的返回结果,只有返回结果的状态是resolved情况,才会把返回结果赋值给result。await不是同步编程,是异步编程(微任务),当代码执行到await时,先把此行执行,构建一个异步的微任务,等待Promise返回结果,并且await下面的代码也都被放到任务队列中。
17、如果Promise的返回结果是失败状态,则await不会接收其返回结果,await下面的代码永远也不会继续执行,await只能处理Promise为成功状态的结果。


1.2、promise的执行方式

1.2.1、成功

let promisee = new Promise((resolve, reject) => {
    
    
	resolve('ok');
	// resolve是成功状态的函数,
	// 对应then中的第一个函数,即result
});

// 设置成功或者失败后处理的方法
promisee.then(result => {
    
    
	console.log('成功:', result); 
	// 成功: ok
}, reason => {
    
    
	console.log('失败:', reason);
});

1.2.2、失败

let promisee = new Promise((resolve, reject) => {
    
    
	reject('no');
	// reject是失败状态的函数,
	// 对应then中的第二个函数,即reason
});

// 设置成功或者失败后处理的方法
promisee.then(result => {
    
    
	console.log('成功:', result);
}, reason => {
    
    
	console.log('失败:', reason); 
	// 失败: no
});

1.2.3、概念中的第7条

new Promise((resolve, reject) => {
    
    
	// 第一组
	// 这里执行完 resolve 后,
	// reject 执行也没有用了,
	// 不会再改变状态了,
	// 下同。
	resolve(1);
	reject(0);
	
	// 第二组
	// reject(0);
	// resolve(1);
}).then(result => {
    
    
	console.log(`成功:${
      
      result}`); 
	// 成功:1
}, reason => {
    
    
	console.log(`失败:${
      
      reason}`);
});

1.2.4、new Promise(resolve => { }).then().then()

new Promise(resolve => {
    
    
	resolve(a);
}).then(result => {
    
    
	console.log(`成功:${
      
      result}`);
	return Promise.reject(result);
}, reason => {
    
    
	console.log(`失败:${
      
      reason}`);
	// 失败:ReferenceError: a is not defined
}).then(resolve => {
    
    
	// 为什么这里进入成功函数,
	// 是因为上一个进入失败函数执行没有报错,
	// 不是说上一个进入了失败函数,
	// 下一个then也进入失败函数。
	console.log(`成功:${
      
      resolve}`);
	// 成功:undefined
	// 这里的value为undefined的原因是,
	// 上一个函数没有return实际的值,
	// 所有的函数如果没有return实际都会返回undefined
}, reason => {
    
    
	console.log(`失败:${
      
      reason}`);
});

1.2.5、Promise.resolve(1).then().then(),reject同理

Promise.resolve(1).then(result => {
    
    
	console.log('成功:', result); 
	// 成功: 1
}, reason => {
    
    
    console.log('失败:', reason);
}).then(result => {
    
    
    console.log('成功:', result); 
    // 成功: undefined
}, reason => {
    
    
    console.log('失败:', reason);
});

1.2.6、顺延和catch

Promise.reject(10).then(result => {
    
    
	console.log(`成功:${
      
      result}`);
	return result * 10
}).then(null, reason => {
    
    
	// 第一个then中没有reason函数,
	// 所以这个reject执行的结果顺延到了第二个then的reason函数。
	console.log(`失败:${
      
      reason}`); 
	// 失败:10
});

Promise.reject(10).then(result => {
    
    
	console.log(`成功:${
      
      result}`);
	return result * 10
}).then(result => {
    
    
	console.log(`成功:${
      
      result}`);
}).catch(reason => {
    
    
	// catch是专门捕获异常的方法,
	// 因为第一和第二个then中都没有reason函数,
	// 所以走到catch才有输出。
	console.log(`失败:${
      
      reason}`); 
	// 失败:10
});

Promise.resolve(10).then(result => {
    
    
	console.log(a);
}).catch(reason => {
    
    
	// 虽然executor中的resolve执行的结果是成功的,
	// 但是第一个then中的result执行的结果是失败的,
	// 所以最后catch捕获到的就是失败的结果。
	console.log(`失败:${
      
      reason}`);
	// 失败:ReferenceError: a is not defined
});

1.2.7、all和race

let p1 = Promise.resolve(1);

let p2 = new Promise(resolve => {
    
    
	setTimeout(_ => {
    
    
		resolve(2);
	}, 1000)
});

let p3 = Promise.reject(3);

Promise.all([p1, p2, p3]).then(result => {
    
    
	console.log(`成功:${
      
      result}`);
}).catch(reason => {
    
    
	console.log(`失败:${
      
      reason}`); 
	// 失败:3
});

Promise.all([p2, p1]).then(result => {
    
    
	// 返回的结果是按照arr中编写实例的顺序组合在一起
	console.log(`成功:${
      
      result}`); 
	// 成功:2,1
}).catch(reason => {
    
    
	console.log(`失败:${
      
      reason}`);
});

2、async/await的使用方式

async function fun(i) {
    
    
	let isIndex = await i == 1 ? '进行中' : '已完成';
	console.log(isIndex); 
    // fun(1); 进行中
    // fun(2); 已完成
            
	return isIndex;
};

console.log(fun(1)); 
// Promise {<pending>}
console.log(fun(2)); 
// Promise {<pending>}

1、回调地狱

1.1、概念

多层回调函数的相互嵌套,就形成了回调地狱。


1.2、回调地狱的缺点

1.2.1、代码耦合性太强,牵一发而动全身,难以维护
1.2.2、大量冗余的代码相互嵌套,代码的可读性变差

1.3、代码

setTimeout(() => {
    
    
    console.log('延迟1秒');
    setTimeout(() => {
    
    
        console.log('延迟2秒');
        setTimeout(() => {
    
    
            console.log('延迟3秒');
        }, 3000);
    }, 2000);
}, 1000);

2、解决回调地狱

2.1、Promise的基本概念

2.1.1、Promise是一个构造函数

● 我们可以创建 Promise 的实例 const p = new Promise()
● new 出来的 Promise 实例对象,代表一个异步操作


2.1.2、Promise.prototype上包含一个.then()方法

● 每一次 new Promise() 构造函数得到的实例对象,
● 都可以通过原型链的方式访问到 .then() 方法,例如 p.then()


2.1.3、.then()方法用来预先指定成功和失败的回调函数

● p.then(成功的回调函数,失败的回调函数)
● p.then(result => { }, error => { })
● 调用 .then() 方法时,成功的回调函数是必选的、失败的回调函数是可选的


2.2、.then()方法的特性

如果上一个.then()方法中返回了一个新的Promise实例对象,则可以通过下一个.then()继续进行处理。通过.then()方法的链式调用,就解决了回调地狱的问题。


2.3、通过.catch捕获错误

在Promise的链式操作中如果发生了错误,可以使用Promise.prototype.catch方法进行捕获和处理。
如果不希望前面的错误导致后续的.then()无法正常执行,则可以将.catch的调用提前。

function func1() {
     
     
  return new Promise((resolve) => {
     
     
    setTimeout(() => {
     
     
      resolve("func1 1000");
    }, 1000);
  });
};

function func2() {
     
     
  return new Promise((resolve) => {
     
     
    setTimeout(() => {
     
     
      resolve("func1 2000");
    }, 2000);
  });
};

function func3() {
     
     
  return new Promise((resolve) => {
     
     
    setTimeout(() => {
     
     
      resolve("func1 3000");
    }, 3000);
  });
};

func1()
 .catch(err => {
     
      console.log(err); })
 .then((result) => {
     
     
    console.log(result);
    return func3();
  })
 .then((result) => {
     
     
    console.log(result);
   return func2();
  })
 .then((result) => {
     
     
    console.log(result);
  });

猜你喜欢

转载自blog.csdn.net/weixin_51157081/article/details/134793217
今日推荐