异步:每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。
改变程序正常执行顺序,不阻塞线程。
具体可以参考我上一篇文章一道关于js宏任务、微任务面试题引发的思考
在浏览器端,耗时长的操作都应该异步执行,避免浏览器失去响应,最好的例子就是Ajax操作。
js中处理异步编程主要有以下几种:
1.回调函数
2.事件监听
3.发布/订阅
4.promise
今天来总结一下promise的概念和用法:
promise概念
promise是一个对象,是由 CommonJS 小组的成员在 Promises/A 规范中提出来的,它是用来处理异步操作的,能让我们在异步调用的时候不会像传统的回调函数那样繁琐,而是更美观更便于阅读,更合理更强大。而es6将其写进了语法标准,统一了用法。
promise用法
promise有三种状态:
1.pending(进行中)
2.resolved(完成) ,fullfiled
3.rejected(失败)
promise两种过程:
1.pending->resolved
2.pending->rejected
Promise对象有一个then方法,用来执行回调函数,该方法接受两个参数,一个是成功的resolved回调,另一个是失败的rejected回调,第二个失败的回调参数可选,并且.then()可以链式调用。
1.promise用new构建
new Promise(function(resolve,reject){});
var p = new Promise(function (resolve, reject) {
console.log('执行操作1');
var num = Math.floor(Math.random()*10);
if(num>5){
resolve(num);
}else{
reject(new Error());
}
});
p.then(function (data) {//num大于5成功
console.log(data);
console.log('这是成功操作');
},function(data){//num小于等于5失败
console.log(data);
console.log('这是失败操作');
});
2.参数resolve是将Promise的状态置为fullfiled,reject的状态置为rejected。
3.常用的静态方法:all, race, reject,resolve等,原型对象上有有catch, then等方法。
静态方法调用直接Promise.all/Promise.race等;
原型对象的方法需要一个Promise的实例( new Promise )。
- .then()可以链式操作
如下:依次弹出1,2,3
function count(n){
return new Promise(function(resolve,reject){
setTimeout(function(){
resolve(n);//成功
},1000)
})
}
count(1).then(function(val){
console.log(val);
return count(2);
}).then(function(val){
console.log(val);
return count(3);
}).then(function(val){
console.log(val);
})
- .catch()也是处理reject传递(处理发生错误)
上面的代码可以改成
var p = new Promise(function (resolve, reject) {
console.log('执行操作1');
var num = Math.floor(Math.random()*10);
if(num>5){
resolve(num);
}else{
reject(new Error());
}
});
p.then(function (data) {
console.log(data);
console.log('这是成功操作');
}).catch(function(data){//
console.log(data);
console.log('这是失败操作');
});
不管是.then()还是catch都会返回一个新建的promise对象
6.Promise.all 接受一个元素为promise对象的数组为参数,成功和失败的返回值是不同的,当所有对象返回resolve时,返回的是一个结果数组,而有一个返回reject时候则返回最先被reject失败状态的值。
Promise.all是等所有的异步资源都加载完毕之后,再执行代码,比如。
例如页面loading效果。
Promise.all主要解决的是多个异步模块的依赖问题,必须等大家都加载完毕之后,才执行,也就是等最慢的那个异步操作执行完了,再打印出结果 。
先看成功的代码
var p1 = new Promise(function(resolve,reject){
setTimeout(function(){
resolve("p1");
},1000)
})
var p2 = new Promise(function(resolve,reject){
setTimeout(function(){
resolve("p2");
},3000)
})
Promise.all([p1,p2]).then(function(data){
console.log(data);
console.log("执行代码")
})
打印结果为["p1","p2"] 执行代码
(这里面打印时间是按照3000)
下面返回reject的代码
var p1 = new Promise(function(resolve,reject){
setTimeout(function(){
resolve("p1");
},1000)
})
var p2 = new Promise(function(resolve,reject){
setTimeout(function(){
reject(new Error);
},3000)
})
Promise.all([p1,p2]).then(function(data){
console.log(data);
console.log("执行代码")
},function(data){
console.log(data);
})
打印结果为Error
6.Promise.race就是赛跑的意思,就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
var p3 = new Promise(function(resolve,reject){
setTimeout(function(){
resolve("p1");
},1000)
})
var p4 = new Promise(function(resolve,reject){
setTimeout(function(){
reject(new Error);
},2000)
})
Promise.race([p3,p4]).then(function(data){
console.log(data);
console.log("执行代码1")
}).catch(function(data){
console.log(data);
console.log("失败");
})
//p1
//执行代码1
最后说一下async:
async 是“异步”的意思,而 await 是等待的意思。所以应该很好理解 async 用于申明一个 function是异步的(实际上是async function 对象),而 await 用于等待一个异步任务执行完成。
也就是说async告诉程序这个方法是存在异步操作,await是一个操作符,即 await 后面是一个表达式。
用法:
1.async 一个async函数,await只能用在这个函数里面。
2.async 函数返回的是一个 Promise 对象
async function testAsync() {
return "hello async";
}
const result = testAsync();
console.log(result);
如果没有await,输出的是如下图
async 函数(包含函数语句、函数表达式、Lambda表达式)会返回一个 Promise 对象,如果在函数中 return 一个直接量,async 会把这个直接量通过 Promise.resolve() 封装成 Promise 对象。
所以要想获取数据,需要.then
Async().then(v => {
console.log(v); // 输出 hello async
});
3.await 表示在这里等待异步操作返回结果,再继续执行。
await 可以用于等待一个 async 函数的返回值,它不仅仅用于等 Promise 对象,它可以等任意表达式的结果,所以,await 后面实际是可以接普通函数调用或者直接量的。
这里借用阮一峰老师的解释:
async 函数返回一个 Promise 对象,当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。
function fn(){
return new Promise(function(resolve,reject){
setTimeout(function(){
resolve("成功")
},1000);
})
}
async function A(){
var v = await fn();
console.log(v);
console.log(123);
}
A();
//成功
//123
其实async结果和之前的 Promise 实现是一样的,如果有多个 Promise 组成的 then 链时,它会看起来更清晰,几乎跟同步代码一样。
await 命令后面的 Promise 对象,运行结果可能是 rejected,所以最好把 await 命令放在 try...catch 代码块中。
async function myFunction() {
try {
await somethingThatReturnsAPromise();
} catch (err) {
console.log(err);
}
}
// 另一种写法
async function myFunction() {
await somethingThatReturnsAPromise().catch(function (err){
console.log(err);
});
}
具体可以查阅阮一峰老师的文章
async 函数的含义和用法