乐趣区

关于javascript:我在乐字节学习前端的第七天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”>async 与 await 封装 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>

退出移动版