Promise以及async...await

1、Promise——解决回调地狱

在这里插入图片描述

  • Promise是一个构造函数
    const p1 = new Promise()    //表示一个异步的操作
    
  • Promiseb本身上有all、reject、resolve等方法,Promise.protype原型上包含.then 、.catch等方法用于处理异步状态成功失败的回调
    Promise.protype.then()   ——>  p1.__proyo__.then()  //原型链
    
  • 三种状态
   > //一般将Promise放在一个函数当中
   > function runAsync(){  
   >  //Promise的构造函数需要我们传入一个函数作为参数,这个函数两个形参resolve和reject来决定状态
   >  var p = new Promise(function(resolve, reject){ 
  >      //异步操作
   >     $.ajax({
   >    		url: 'xxx.com',
   >    		data: {name:'krry'},
   >    		success: res => {
   >      		resolve(res); // 成功
   >    		},
   >    		error: err => {
   >      		reject(err); // 失败
   >   		 }
 >  	})
 >    });
   >  return p;
   > }
  • 异步操作"未完成"(pending)

    • 异步操作"已完成" (resolved),对应状态为fullfiled
    • 异步操作"失败" (rejected),对应状态为rejected

    这三种状态的变化途径只有2种:
    1,异步操作从“未完成”pending到”已完成“resolved
    2,异步操作从“未完成"pending到”失败“rejected

状态一旦改变,就无法再次改变状态,这也是它名字 promise-承诺 的由来

所以Promise对象的最终结果只有两种:

1,异步操作成功 Promise 对象传回一个值,状态变为 resolved
2,异步操作失败 Promise 对象抛出一个错误,状态变为 rejected

  • .then()

    1、then接收两个参数,并且这两个参数都是带有各自参数的函数,前者为成功时的函数,后者为失败时的函数(第二个参数是可选参数)

    2、then函数返回一个Promise

    ​ 若传入的函数并没有返回值,则将undefined作为下一个Promise的data;

    ​ 若传入的函数返回值是一个普通值(非Promise),则将这个值作为下一个Promise的data;

    ​ 若传入的函数返回值是一个Promise,则等待这个Promise的决议完成,再将这个结果作为下一个Promise的返回值。

    //then 方法有两个参数,第一个是成功 resolve 的回调,第二个是失败 reject 的回调
    runAsync().then(data => {
      console.log(data);  // 请求到的数据
      console.log('请求数据成功!');
    }, err => {
      // 这是 then 的第二个参数,请求失败 reject 的回调
     console.log('请求失败!');
    });
    
  • .catch()

    相当于 then 的第二个参数,失败 reject 的回调

    runAsync().then(data => {
      console.log(data);  // 请求到的数据
      console.log('请求数据成功');
    }).catch(err => {
      // 这是 catch,请求失败 reject 的回调
      console.log('请求失败');
    });
    
  • 解决回调地狱
    做异步请求的时候,在请求成功的回调函数里继续写函数,或者继续发送异步,继续回调,回调函数里又回调,一层一层,嵌套越来越多,就会形成回调地狱。这会使我们的代码可读性变差,不好维护,性能也下降。
    

    Promise 就是用同步的方式写异步的代码,用来解决回调问题

  • Promise.all()和Promise.race()

1、Promise.all(),将多个Promise实例包装成一个新的Promise实例(等待机制)

//成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。

//所有的异步操作结束之后才会执行下一步的then(),可以保障promise请求的顺序
let wake = (time) => {
return new Promise((resolve, reject) => {
 setTimeout(() => {
   resolve(`休眠${time}ms`)
 }, time)
})
}

let p1 = wake(3000)
let p2 = wake(2000)

Promise.all([p1, p2]).then((result) => {
console.log(result)       // [ '休眠3s', '休眠2s' ]
}).catch((error) => {
console.log(error)
})
注意的是,Promise.all获得的成功结果的数组里面的数据的顺序,和Promise.all接收到的数组顺序是会一致的,即p1的结果在前,即便p1的结果获取的比p2要晚,。这带来了一个绝大的好处:在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all毫无疑问可以解决这个问题。
``
  2、Promise.race() (赛跑机制)
//一个异步操作完成,立即就会执行下面的代码
//Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
 resolve('success')
},1000)
})

let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
 reject('failed')
}, 500)
})

Promise.race([p1, p2]).then((result) => {
console.log(result)
}).catch((error) => {
console.log(error)  // 打开的是 'failed'
})

2、async … await ——简化Promise的操作(同步写法)

注意点:

  • await只能放在async函数里

  • 在async…await中,第一个await之前的代码是同步执行,之后的代码是异步执行

    console.log('1')
    async function getData(){
      console.log('2')
      let res1 = await axios.get('/user')
      console.log('3')
    }
    console.log('4')
    结果:1 2 4 3
    
  • 分布解析async

async函数,async 函数(有函数语句、函数表达式、Lambda表达式)会返回一个 Promise 对象

async function testAsync() {
    return "hello async";  //返回一个直接量
}

//如果在函数中 `return` 一个直接量,async 会把这个直接量通过 `Promise.resolve()` 封装成 Promise 对象

const result = testAsync();
console.log(result);   //输出Promise { 'hello async' }一个promise对象

**注:**Promise.resolve(x) 可以看作是 new Promise(resolve => resolve(x)) 的简写

返回一个promise对象,就可以then()来处理

testAsync().then(v => {
    console.log(v);    // 输出 hello async
});

如果 async 函数没有返回值,它会返回 Promise.resolve(undefined)

Promise 的特点是异步的,无需等待,所以在没有 await 的情况下执行 async 函数,它会立即执行,返回一个 Promise 对象,并且,绝不会阻塞后面的语句。这和普通返回 Promise 对象的函数并无二致。

  • 分布解析await

一般来说,都认为 await 是在等待一个 async 函数完成。不过按语法说明,await 等待的是一个表达式,这个表达式的计算结果是 Promise 对象或者其它值。

await要配合await来使用,await意思是等待,从他的语法书写可以看出, 它是在等待后面代码执行完成,即等待一个 async 函数的返回值

上面说了async是可以返回一个直接量,或者任意的返回值,所以await 后面实际是可以接普通函数调用或者直接量的

function getSomething() {
    return "something";
}

async function testAsync() {
    return Promise.resolve("hello async");
}

async function test() {
    const v1 = await getSomething();
    const v2 = await testAsync();
    console.log(v1, v2);
}

test();

await 可以看做是个一个处理异步运算符,用于组成表达式,await 表达式的运算结果取决于它等的东西。

如果它等到的不是一个 Promise 对象,那 await 表达式的运算结果就是它等到的东西。await 等待的不是一个 Promise Like 对象的时候,相当于 await Promise.resolve(...)

如果它等到的是一个 Promise 对象,await 就忙起来了,它会阻塞后面的代码,等着 Promise 对象 resolve,然后得到 resolve 的值,作为 await 表达式的运算结果。

  • async/await组合解析

async 会将其后的函数(函数表达式或 Lambda)的返回值封装成一个 Promise 对象,而 await 会等待这个 Promise 完成,并将其 resolve 的结果返回出来。

举例,用 setTimeout 模拟耗时的异步操作,先来看看不用 async/await 会怎么写

function takeLongTime() {
 return new Promise(resolve => {
     setTimeout(() => resolve("long_time_value"), 1000);
 });
}
takeLongTime().then(v => {
 console.log("got", v);
});

如果改用 async/await 呢,会是这样

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

//takeLongTime() 没有申明为 async。实际上,takeLongTime() 本身就是返回的 Promise 对象,加不加 async 结果都一样
async function test() {
 const v = await takeLongTime();
 console.log(v);
}

test();

如果一个函数本身就返回 Promise 对象,加 async 和不加 async 还是有一点点区别:加了 async 之后外面得到 Promise 对象并不是 return 的那一个,参阅代码:

(() => {
    let promise;
    async function test() {
        promise = new Promise(resolve => resolve(0));
        promise.mark = "hello";
        return promise;
    }

    const gotPromise = test();
    console.log(`is same object?: ${promise === gotPromise}`);  // false
    console.log(`promise.mark: ${promise.mark}`);               // hello
    console.log(`gotPromise.mark: ${gotPromise.mark}`);         // undefined
})();

了解这一点后,如果我们需要在返回的 Promise 对象上附加一些东西,比如 cancel(),就得小心一点。

  • async/await 的优势在于处理 then 链

    promise解决了回调地狱的问题,async…await作为语法糖,简化promise的繁琐的then的链式写法,以同步的方式表达出来

    本文相关链接:https://segmentfault.com/a/1190000007535316

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值