Promise和async/await

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){
     resolve("a函数");
  });
}
//第二个异步任务
function b(data_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

原文地址:https://www.cnblogs.com/wenxuehai/p/11306245.html

时间: 2024-10-08 12:27:15

Promise和async/await的相关文章

node.js异步控制流程 回调,事件,promise和async/await

写这个问题是因为最近看到一些初学者用回调用的不亦乐乎,最后代码左调来又调去很不直观. 首先上结论:推荐使用async/await或者co/yield,其次是promise,再次是事件,回调不要使用. 接下来是解析,为什么我会有这样的结论 首先是回调,理解上最简单,就是我把任务分配出去,当你执行完了我就能从你那里拿到结果执行相应的回调, 这里演示一个对setTimeout的封装,规定时间后打印相应结果并执行回调函数 并且这个函数传给回调函数的参数符合node标准,第一个为error信息,如果出错e

callback vs async.js vs promise vs async / await

需求: A.依次读取 A|B|C 三个文件,如果有失败,则立即终止. B.同时读取 A|B|C 三个文件,如果有失败,则立即终止. 一.callback 需求A: let read = function (code) { if (code) { return true; } else { return false; } } let readFileA = function (callback) { if (read(1)) { return callback(null, "111");

Promise和Async/Await用法整理

1.Promise 1.简介 Promise,简单来说就是一个容器,里面保存着某个未来才会结束的时间(通常是一个异步操作的结果) Promise对象的基本语法: new Promise((resolve,reject) => { //..... }); 从语法上来说,Promise是一个对象,从它可以获取异步操作的消息. 基本语法: let p = new Promise((resolve,reject) => { //... resolve('success') }); p.then(res

重构:从Promise到Async/Await

摘要: 夸张点说,技术的发展与历史一样,顺之者昌,逆之者亡.JS开发者们,赶紧拥抱Async/Await吧! GitHub仓库: Fundebug/promise-asyncawait 早在半年多之前,我就在鼓吹Async/Await替代Promise的6个理由,似乎还招致了一些批评.然而,直到最近,我才真正开始进行代码重构,抛弃Promise,全面使用Async/Await.因为,Node 8终于LTS了! Async/Await真的比Promise好吗? 是的是的. 这些天,我大概重构了10

异步 callback vs promise vs async/await

1. callback var fn1=function(){console.log("func1")} var fn2=function(fn){ setTimeout(function(){ console.log("func2") fn() //不能写fn,这只是函数名,要写fn()才是触发 },500)}var fn3=function(){console.log("func3")} //函数名作为参数传入fn2 fn1()fn2(fn3

用promise和async/await分别实现红绿灯

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" con

promise和async/await的用法

promise和async都是做异步处理的, 使异步转为同步 1.promise 它和Promise诞生的目的都是为了解决“回调地狱”, promise使用方法: <button @click="testBtn()">点击</button> get(data) { return new Promise((resolve, reject)=>{ if (data > 5) { resolve(data); } else { reject("数

js中回调函数,promise 以及 async/await 的对比用法 对比!!!

在编程项目中,我们常需要用到回调的做法来实现部分功能,那么在js中我们有哪些方法来实现回调的? 方法1:回调函数 首先要定义这个函数,然后才能利用回调函数来调用! login: function (fn) { var app = getApp() wx.login({ success: res => { let code = res.code; wx.getSetting({ success: res => { if (res.authSetting['scope.userInfo']) {

理解异步之美:Promise与async await(一)

你可能会放出一个怪物 异步与同步相比,最难以掌控的就是异步的任务会什么时候完成和完成之后的回调问题, 难以掌控的触发状态,让你自己写的代码当时还可以读懂,但是过几天.半个月之后如果不重新盘一边逻辑,你哪知道哪个内容会先执行,借用这么一个例子 listen( "click", function handler(evt){ setTimeout( function request(){ ajax( "http://some.url.1", function respon