加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

Promise和async/await

发布时间:2020-12-15 05:26:49 所属栏目:Java 来源:网络整理
导读:1、promise对象 promise 对象有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。promise 对象的状态改变,只有两种可能:从 pending 变为 fulfilled 和从 pending 变为 rejected。 const promise = new Promise( function (resolve

1、promise对象

promise 对象有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。promise 对象的状态改变,只有两种可能:从 pending 变为 fulfilled 和从 pending 变为 rejected。

const promise = new Promise(function(resolve,reject) {
  if (){
    resolve(value);
  } else {
    reject(error);
  }
});

promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 和 reject,它们是两个函数,由 JavaScript 引擎提供,不用自己部署。

resolve 函数将 promise 对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved)可以将数据作为参数传递出去。reject 函数的作用是,将 promise 对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),也可以将某些错误信息作为参数传递出去。

由于Promise 新建后会立即执行,所以可以在 promise 外面再包裹一层函数:

function timeout(ms) {
  return new Promise((resolve,reject) => {
    setTimeout(resolve,ms,‘done‘);
  });
}

timeout(100).then((value) => {
  console.log(value);
});

?

1.1、then() 方法

Promise 实例是一个对象,不是一个函数。promise?实例生成以后,可以用 then 方法分别指定 resolved?状态和 rejected?状态的回调函数。

let promise = new Promise(function(resolve,reject) {
  if (){
    resolve(value);
  } else {
    reject(error);
  }
});

promise.then(function(value) {
  console.log(value)
},function(error) {
  console.log(error)
});

then 方法可以接受两个回调函数作为参数。第一个回调函数是 promise 对象的状态变为 resolved 时调用,第二个回调函数是 promise 对象的状态变为 rejected 时调用,第二个函数是可选的,不一定要提供。这两个函数都接受 promise 对象传出的值作为参数。

?

1.2、then() 方法的链式写法

then?方法返回的是一个新的 promise?实例,因此可以采用链式写法,即 then 方法后面再调用另一个 then 方法。

1.2.1、then 方法里面返回一个确定值时

在一个 then() 方法里面你可以 return 一个确定的“值”,此时?then 会将这个确切的值传入一个默认的新的 Promise 实例,并且这个 Promise 实例会立即置为 fulfilled 状态,将 return 的值作为 resolve 方法的参数传递出去,以供接下来的 then 方法里使用。

let p1 = new Promise((resolve,reject) => {
    resolve(‘aaa‘)
})
p1.then((data) => {
    data = data + ‘bbb‘
    return data  // 此时data会作为resolve的参数传递出去
}).then((val) => {
    console.log(val + ‘ sucess‘);
},(err) => {
    console.log(err + ‘ error‘);
})

//输出: aaabbb sucess

?

1.2.1、then 方法里面返回一个 promise 实例

如果 then 方法里面返回的还是一个 promise 对象,这时后一个回调函数,就会等待该 promise 对象的状态发生变化,才会被调用。

//第一个异步任务
function a(){
  return new Promise(function(resolve,reject){
     resolve("a函数");
  });
}
//第二个异步任务
function b(data_a){
  return new Promise(function(resolve,reject){
     console.log(data_a);
     resolve("b函数");
  });
}

//连续调用
a().then(function(data){   
    return b(data);      // 此时then方法里面返回的是一个promise对象,后面的then会等待该promise对象的状态发生改变才会被调用
}).then((data) => {
    console.log(data + ‘sucess‘)
},(err) => {
    console.log(err + ‘rejected‘)
})
//输出:a函数  b函数sucess

上面的最后一个 then 函数等待前面的 then 函数里面的 promise 对象状态发生改变,如果变为 resolved?,就调用第一个回调函数,如果状态变为 rejected,就调用第二个回调函数。

1.2.1、then 方法里面不返回

如果 then 方法不返回数据,那么后面的 then 将无法获取到前面的数据,但是后面的 then 方法仍能执行。

//第一个异步任务
function a(){
  return new Promise(function(resolve,reject){
     console.log(data_a);
     resolve("b函数");
  });
}

a().then(function(data){   
    console.log(data)    //不返回
}).then((data) => {
    console.log(data + ‘ sucess‘)
},(err) => {
    console.log(err + ‘ rejected‘)
})
//输出: a函数  undefined sucess

?

1.3、catch() 方法

Promise.prototype.catch方法是.then(null,rejection).then(undefined,rejection)的别名,用于指定发生错误时的回调函数。

p.then((val) => console.log(val))
  .then(null,(err) => console.log(err));
// 相当于
p.then((val) => console.log(val))
  .catch((err) => console.log(err));

catch 方法中断调用链:

在很多情况下,如果连续的几个异步任务,其中某个异步任务处理失败,那么接下来的几个任务很大程度上就不需要继续处理了,我们可以使用 catch 方法来终止then的调用链。

function a() {
   return new Promise(function (resolve,reject) {
       setTimeout(function () {
         reject("error");
       },1000);
   });
}

//这样做不会中断
//下面输出:222  333
a().then(function (data) {
   console.log(111);
   return data
},function (data) {  //如果是这样处理rejected状态,并不会中断调用链
   console.log(222);        
   return data;
}).then(function (data) {
   console.log(333);
})

//在调用链的末尾加上catch方法,当某个环节的Promise的异步处理出错时,将中断其后的调用,直接跳到最后的catch
//下面直接输出: ‘error‘
a().then(function (data) {
   console.log(111);
   return data
}).then(function (data) {
   console.log(222);
}).catch(function (e) {
   //rejected的状态将直接跳到catch里,剩下的调用不会再继续
   console.log(e);
});

使用 catch 方法时,如果前面的函数里面有 reject 或者函数里面有错误的话,就会被 catch 方法捕获,立即跳转到 catch 方法里执行。前面的回调函数中,不管是运行中有错误,或者是执行了 reject ,都会立即被?catch?方法捕获。

?

2、async/await 方法

async 方法里面有 await 命令,await 命令后面跟着异步操作(可以是请求接口或者其他异步操作等),这时 async 函数会停下来,等待 await 命令后面的异步操作执行完毕,将结果返回,然后再继续执行下去。如果后面再遇到 await 命令仍是如此,所以,async 函数里面可以看做是同步操作,语句都是一行一行地依次执行的,语句执行顺序非常清晰。

2.1、async 函数的定义形式

// 函数声明
async function foo() {}

const foo = async function () {};

// 对象的方法
let obj = { async foo() {} };

// 箭头函数
const foo = async () => {};

// Class 的方法
class Storage {
  constructor() {
    this.cachePromise = caches.open(‘avatars‘);
  }

  async getAvatar(name) {
    const cache = await this.cachePromise;
    return cache.match(`/avatars/${name}.jpg`);
  }
}

2.2、async 函数里面的 await 命令

2.2.1、await 跟着 promise 对象

一般来说,await命令后面应该跟着一个 Promise 对象,如果该 promise 对象触发的是 resolve 方法,那么就会将 resolve 方法的参数返回。

function timeout() {
  return new Promise((resolve) => {
      setTimeout(function (){
              resolve(‘aaa‘)
      },1000);
  });
}
async function asyncPrint() {
   let data = await timeout();
   console.log(111);
   console.log(data);
}
asyncPrint(); //按顺序执行,1秒后依次输出 111 aaa

?

如果是 reject 方法,则reject的参数会被后面第一个出现的catch方法的捕获到。

reject 情况下可以被 async 函数外部的 catch 方法捕获到(其实此时相当于async函数返回了一个rejected状态的promise对象)。

下面代码中,await语句前面没有return,但是reject方法的参数依然传入了catch方法的回调函数。这里如果在await前面加上return,效果是一样的。

async function f() {
  await Promise.reject(‘出错了!!‘);
}

f().then(v => console.log(v)).catch(e => console.log(e))   //输出: 出错了!!

任何一个await语句后面的 Promise 对象变为reject状态,那么整个async函数都会中断执行。

async function f() {
  await Promise.reject(‘出错了‘);
  await Promise.resolve(‘hello world‘); // 不会执行
}

有时,我们希望即使前一个异步操作失败,也不要中断后面的异步操作。这时可以将第一个await放在try...catch结构里面,这样不管这个异步操作是否成功,第二个await都会执行。

async function f() {
  try {
    await Promise.reject(‘出错了‘);
  } catch(e) {
  }
  return await Promise.resolve(‘helloworld‘);
}

f().then(v => console.log(v))   //输出: helloworld

?

2.2.2、await 跟着确定的值

如果 await 命令后面不是 Promise 对象,就直接返回对应的值。

async function f() {
  // 等同于 return 123;
  let a = await 123;
  console.log(a)
}
f();   //输出: 123

?

2.3、async 函数返回的是一个 promise 对象

async函数返回的是一个 Promise 对象,可以使用then方法添加回调函数。

async函数内部return语句返回的值,会成为then方法回调函数的参数。

async function f() {
  return ‘hello world‘;
}

f().then(v => console.log(v))
// "hello world"

async函数返回的 Promise 对象,必须等到内部所有await命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。也就是说,只有等到async函数内部的await 后面的异步操作执行全部完,promise 对象状态才会发生改变,然后才能执行后面添加的then方法指定的回调函数。

let p1 = new Promise((resolve,reject)=>{
   resolve(‘aaa‘)
})
let p2 = new Promise((resolve,reject)=>{
   resolve(‘aaa‘)
})
async function getUrl(url) {
   let response = await p1;
   let html = await p2;
   return url;
}
getUrl(‘http://www.baidu.com‘).then((val) => {
   console.log(val)
})    //只有等到 p1 和 p2 都执行完毕后才会调用then里面的回调函数输出值,输出:http://www.baidu.com

?

2.3.1、async 函数的错误处理

如果await后面的异步操作出错,或者是await 后面的 promise 对象被 reject,那么async函数后面的语句将不会执行,async 函数会立即返回一个 rejected 状态的promise对象

async function f() {
  await new Promise(function (resolve,reject) {
    throw new Error(‘出错了‘);
  });
}
f().then(v => console.log(v)).catch(e => console.log(e))
// Error:出错了

async function f() {
  await Promise.reject(‘出错了!!‘);
}
f().then(v => console.log(v)).catch(e => console.log(e))   //输出: 出错了!!

防止出错的方法,也是将其放在try...catch代码块之中。

async function f() {
  try {
     await new Promise(function (resolve,reject) {
        throw new Error(‘出错了‘);
     });
  }catch (e) {}
     return await (‘hello world‘); //这里仍然能执行
  }
f().then((data) => {console.log(data);});    //输出: hello world

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读