我在乐字节学习前端的第七天-Promise学习

一、什么是Promise?

Promise 是 ES6 引入的进行异步编程的新的解决方案。
备注:旧的是单纯的回调函数

从语法上来说:它就是一个构造函数,可以封装异步的任务,并且对结果进行处理。
从功能上来说:Promise对象用来封装一个异步操作并可以获取其成功/失败 的结果值。

Promise最大的好处在于可以解决回调地狱的问题,并且它在指定回调与错误处理这块要更加的灵活与方便,而且Promise在现代项目当中,无论是Web还是App的项目当中都应用的十分广泛,无论是前端还是后端都可以看到它的身影,同时它也是现在面试的高频题目

二、Promise 初体验

2.1 在nodejs环境下读取文件内容

需求:读取当前目录下的 file 文件夹下的 content.txt 的内容并输出。

// 引入fs模块
const fs = require('fs')

// 回调函数形式
// fs.readFile('./file/content.txt', (err, data) => {
//   // 如果错误,则抛出错误
//   if(err) throw err

//   console.log(data.toString());
// })

// Promise新式
let p = new Promise((resolve, reject) => {
  fs.readFile('./file/content.txt', (err, data) => {
    if (err) reject(err);
    resolve(data);
  })
})

p.then(value =>{
  console.log(value.toString());
},reason =>{
  console.log(reason);
})

output:

Hello Promise,This is Content
1

2.2 封装 AJAX

需求:使用Promise封装AJAX并读取接口数据并输出
接口地址: https://api.apiopen.top/getJoke

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <!-- 引入bootstrap 的样式 -->
  <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.css">
</head>
<body>
  <div class="container">
    <h2 class="page-header">Promise 封装 AJAX操作</h2>
    <button class="btn btn-primary" id="btn">点击发送AJAX</button>
  </div>
  <script>

    const btn = document.querySelector('#btn')
    btn.onclick = function () {
      const p = new Promise((resolve, reject) => {
        xhr = new XMLHttpRequest()
        xhr.open('GET', 'https://api.apiopen.top/getJoke')
        xhr.send()
        xhr.onreadystatechange = function () {
          if (xhr.readyState === 4) {
            if (xhr.status >= 200 && xhr.status < 300) {
              resolve(xhr.response)
            } else {
              reject(xhr.status)
            }
          }
        }
      })
      p.then(value => {
        console.log(value);
      }, reason => {
        console.warn(reason);
      })

    }
  </script>
</body>
</html>

三、怎么使用 Promise?

在了解怎么使用 Promise之前,我们先来看看 Promise实例对象的两个属性:
「PromiseState」和「PromiseResult」

3.1 Promise 的状态

每一个实例对象都拥有一个属性叫做 「PromiseState」,这个属性有三个值,分别是:

  • pending 「未决定的」
  • resolved / fullfilled 「成功」
  • rejected 「失败」

状态的改变

  1. pending变为 resolved
  2. pending变为 rejected

说明:只有这2种,且一个 promise对象只能改变一次,改变后不可修改
无论变为成功还是失败,都会有一个结果数据
成功的结果数据一般称为 value,失败的结果数据一般称为 reason

3.2 Promise 的结果

每一个实例对象都拥有一个属性叫做 「PromiseResult」
它用于保存实例对象(异步任务) 「成功或失败」 的结果。

只有 resolvereject 可以修改该属性的值。

四、 Promise 的 API

4.1 resolve 方法

如果传入的参数为非 Promise类型的对象,则返回的结果为成功 promise对象
如果传入的参数为 Promise对象,则参数的结果决定了 resolve的结果

const p1 = Promise.resolve(520)
console.log(p1); // PromiseState => fulfilled

const p2 = Promise.resolve(new Promise((resolve, reject) => {
  reject('111')
}))

// 此处内部有一个失败的回调,但是没有处理.所以会产生报错
console.log(p2); // PromiseState => rejected   报错:Uncaught (in promise) 111

p2.catch(reason => {
  console.log(reason); // 111
})

4.2 reject 方法

永远返回一个 rejected「失败」的 Promise 对象。

// const p = Promise.reject(521)
// 注意此处会产生一个报错,原因是内部有一个失败的Promise但是没有对应的回调来处理它
// console.log(p); // PromiseState rejected

const p2 = Promise.reject(new Promise((resolve, reject) => {
  resolve('123')
}))
console.log(p2); // PromiseState rejected
p2.then(value =>{
  console.log(value);
},reason =>{
  console.log(reason); // 失败的结果 是一个 Promise对象,这个Promise对象的状态为成功 
})

4.3 all 方法

语法:

Promise.all(Array) // Array 一组Promise对象
1

说明:返回一个新的 Promise,只有所有的 Promise都成功才成功,只要有一个失败了就
直接失败

第一种情况,全部都是 resolved:

const p1 = new Promise((resolve, reject) => {
  resolve('ok')
})
const p2 = Promise.resolve('success')
const p3 = Promise.resolve('Oh Yeah')

const result = Promise.all([p1, p2, p3])

console.log('result: ', result); 
// PromiseState "fulfilled"
// PromiseResult ['ok','success','Oh Yeah']

第二种情况,有一个是 rejected:

const p1 = new Promise((resolve, reject) => {
  resolve('ok')
})	
const p2 = Promise.reject('error info')
const p3 = Promise.resolve('Oh Yeah')

const result = Promise.all([p1, p2, p3])

console.log('result: ', result);
// PromiseState "rejected"
// PromiseResult "error info"

4.4 race方法

race函数返回一个 Promise,它可以是完成( resolved),也可以是失败(rejected),这要取决于第一个完成的是哪个。

第一种情况,先完成的是 「P1 => resolved」 :

const p1 = new Promise((resolve, reject) => {
  resolve('ok')
})
const p2 = Promise.reject('error')
const p3 = Promise.resolve('Oh Yeah')

const result = Promise.race([p1, p2, p3])
console.log(result); // PromiseState:"fulfilled"  PromiseResult:"ok"

第二种情况,先完成的是 「P2 => rejected」:

//第一钟测试方式:
//注意:这里改变的是race方法参数的位置
const p1 = new Promise((resolve, reject) => {
  resolve('ok')
})
const p2 = Promise.reject('error info')
const p3 = Promise.resolve('Oh Yeah')

const result = Promise.race([p2, p1, p3])
console.log(result); // PromiseState:"rejected"  PromiseResult:"error info"

//第二钟测试方式:
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('ok')
  }, 1000);
})
const p2 = Promise.reject('error info')
const p3 = Promise.resolve('Oh Yeah')

const result = Promise.race([p1, p2, p3])
console.log(result); // PromiseState:"rejected"  PromiseResult:"error info"

4.5 实例对象的 then方法

then 方法拥有返回值,返回值是一个 Promise 对象。状态是由回调函数的执行结果来决定.

  1. 返回结果是非 Primose 类型,状态为成功,返回值为then方法中的返回值(下方例子中的 123即为返回值),方法中如果没有return 则为 undefined
  2. 如果返回值是一个 Promise 对象, 那么内部 Promise 对象返回的状态和值决定外部 then 方法的状态和值
  3. 如果抛出错误,则then方法状态为 rejected,值为抛出的值

提示: then方法的返回值与 async 修饰的函数的返回值一模一样

const p = new Promise((resolve, reject) => {
  resolve('ok')
})

const result = p.then(value => {
  // 1.返回普通数据 状态为成功,没有return状态也为成功,值为undefined
  // return 123;

  // 2.抛出错误,状态为失败,值为抛出的值
  // throw '出错啦'

  // 3.返回一个 Promise ,内部的Promise决定外部then方法的状态及返回值
  return new Promise((resolve, reject) => {
    // resolve()
    // reject()
    throw '出错啦!';
  })
}, err => {
  console.error(err);
})
console.log(result); // PromiseState: "rejected"  PromiseResult: "出错啦!"

特殊情况:

then方法期望的参数是一个函数,如果不是函数则会发生 Promise穿透(值穿透),状态为上一个Promise的状态,值为上一个 Promise的值。

// 特殊情况:
const p = new Promise((resolve, reject) => {
  resolve('ok')
  // reject('error')
})
const result = p.then(console.log(123))
console.log(result); // PromiseState: "fulfilled"  PromiseResult: "ok"
1234567

稍微加点难度:

 Promise.resolve('foo')
	.then(Promise.resolve('bar'))
	.then(function(result){
	  console.log(result)
	})

当然,输出的结果为foo。问其原因,答案如题——Promise值穿透
解释:.then 或者 .catch 的参数期望是函数,传入非函数则会发生值穿透。

再来一道:

Promise.resolve(1)
  .then(function(){return 2})
  .then(Promise.resolve(3))
  .then(console.log)

output: 2
解释:Promise.resolve(3) 不是函数,发生了值穿透

继续来:

Promise.resolve(1)
  .then(function(){return 2})
  .then(function(){return Promise.resolve(3)})
  .then(console.log)

output:3

五、async 和 await

5.1 async

使用 async 关键字 修饰的函数 返回值永远为 Promise 对象,这个Prmose对象的状态与then方法返回值的状态都是应用的同一种规则。

一个最简单的例子:

async function main(){
  
}
let result = main()
console.log(result); // "fulfilled" "undefined"

5.2 await

await 右侧的表达式一般为 promise对象,但也可以是其它的

  1. 右侧没有Promise的情况: 直接将此值作为 await的返回值
  2. 右侧为成功的 Promise: 返回的是 promise成功的值
  3. 右侧为失败的 Promise: 抛出异常,需要使用 try catch 捕获处理

注意:
await 必须写在 async函数中,但 async函数中可以没有 await

async function main() {
  // 1.右侧没有Promise的情况:   直接将此值作为 await的返回值
  let result = await 'str'
  console.log(result); // result => str  info => fulfilled  str
  return result

  // 2.右侧为成功的 Promise:    返回的是 promise成功的值
  // let p1 = new Promise((resolve, reject) => {
  //   resolve('ok')
  // })
  // let result1 = await p1
  // console.log(result1); // result => ok  info => fulfilled  ok
  // return result1

  // 3.右侧为失败的 Promise:  抛出异常,需要使用 try catch 捕获处理
  // let p2 = new Promise((resolve, reject) => {
  //   reject('error')
  // })
  // try {
  //   let result2 = await p2
  // } catch (e) {
  //   console.log(e); // e => error  info => fulfilled  error
  //   return e
  // }
}
const info = main()
console.log(info);

六、async与await 结合发送 AJAX

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <!-- 引入bootstrap 的样式 -->
  <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.css">
</head>

<body>
  <div class="container">
    <h2 class="page-header">asyncawait封装AJAX操作</h2>
    <button class="btn btn-primary" id="btn">点击发送AJAX</button>
  </div>
  <script>
    function sendAJAX(url) {
      return new Promise((resolve, reject) => {
        xhr = new XMLHttpRequest()
        xhr.responseType = 'json'
        xhr.open('GET', url)
        xhr.send()
        xhr.onreadystatechange = function () {
          if (xhr.readyState === 4) {
            if (xhr.status >= 200 && xhr.status < 300) {
              resolve(xhr.response)
            } else {
              reject(xhr.status)
            }
          }
        }
      })
    }

    const btn = document.querySelector('#btn')
    btn.addEventListener('click', async function () {
      let result = await sendAJAX('https://api.apiopen.top/getJoke')
      console.log(result);
    })
  </script>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值