解读Promise

Snipaste_20200513_130258.jpg

Promise基本使用

          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
const p = new Promise((resolve, reject) => { // 1)同步执行的执行器函数 // 2) 在执行器函数中启动异步任务 setTimeout(() => { // 3) 根据结果做不同处理 const time = Date.now() // 3.1) 如果成功了, 调用resolve(), 指定成功的value, 变为resolved状态 if (time % 2 == 1) { resolve('成功的数据 ' + time) console.log('resolve()之后') } else {// 3.2) 如果失败了, 调用reject(), 指定失败的reason, 变为rejected状态 reject('失败的数据 ' + time) } }, 1000); }) // 4) 能promise指定成功或失败的回调函数来获取成功的vlaue或失败的reason p.then( value => { console.log('成功', value) }, error => { console.log('失败', error) } )

Promise的API

  1. Promise构造函数: Promise (excutor) {} excutor函数: 同步执行 (resolve, reject) => {} resolve函数: 内部定义成功时我们调用的函数 value => {} reject函数: 内部定义失败时我们调用的函数 reason => {} 说明: excutor会在Promise内部立即同步回调,异步操作在执行器中执行

  2. Promise.prototype.then方法: (onResolved, onRejected) => {} onResolved函数: 成功的回调函数 (value) => {} onRejected函数: 失败的回调函数 (reason) => {} 说明: 指定用于得到成功value的成功回调和用于得到失败reason的失败回调 返回一个新的promise对象

  3. Promise.prototype.catch方法: (onRejected) => {} onRejected函数: 失败的回调函数 (reason) => {} 说明: then()的语法糖, 相当于: then(undefined, onRejected)

  4. Promise.resolve方法: (value) => {} value: 成功的数据或promise对象 说明: 返回一个成功/失败的promise对象

  5. Promise.reject方法: (reason) => {} reason: 失败的原因 说明: 返回一个失败的promise对象

  6. Promise.all方法: (promises) => {} promises: 包含n个promise的数组 说明: 返回一个新的promise, 只有所有的promise都成功才成功, 只要有一个失败了就直接失败

7.Promise.race方法: (promises) => {} promises: 包含n个promise的数组 说明: 返回一个新的promise, 第一个完成的promise的结果状态就是最终的结果状态

例子

          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
new Promise((resolve, reject) => { setTimeout(() => { // resolve(1) reject(2) }, 1000); }).then(value => { console.log('onResolved()', value) }/* , error=> { console.log('onRejected()', error) } */).catch(error=> { console.log('onRejected2()', error) })

此法来解决回调地狱

          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
//回调地狱 doSomething(function (result) { // 第一个异步任务成功启动第二个异步任务 doSomethingElse(result, function (newResult) { // 第二个异步任务成功启动第三个异步任务 doThirdThing(newResult, function (finalResult) { // 第三个异步任务成功了 console.log('Got the final result: ' + finalResult) }, failureCallback) }, failureCallback) }, failureCallback) //链式调用解决回调地狱 doSomething() .then(function (result) { return doSomethingElse(result) }) .then(function (newResult) { return doThirdThing(newResult) }) .then(function (finalResult) { console.log('Got the final result: ' + finalResult) }) .catch(failureCallback)

Promise.all 全成功才行

          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
const p1 = new Promise((resolve, reject) => { setTimeout(() => { resolve(1) }, 1000); }) const p2 = Promise.resolve(2) const p3 = Promise.reject(3) const p4 = Promise.reject(4) p1.then(value => console.log('p1 value', value)) p2.then(value => console.log('p2 value', value)) p3.catch(reason => console.log('p3 value', reason)) p4.catch(reason => console.log('p4 value', reason)) const pa = Promise.all([p1, p2, p3, p4]) // const pa = Promise.all([p1, p2]) pa.then( values => console.log('pa all onResolved()', values), // 数据的顺序与promise数组顺序一致,不是按先后 reason => console.log('pa all onRejected()', reason), )

Promise.race 谁先取谁

          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
const p1 = new Promise((resolve, reject) => { setTimeout(() => { resolve(1) }, 1000); }) const p2 = Promise.resolve(2) const p3 = Promise.reject(3) const p4 = Promise.reject(4) p1.then(value => console.log('p1 value', value)) p2.then(value => console.log('p2 value', value)) p3.catch(reason => console.log('p3 value', reason)) p4.catch(reason => console.log('p4 value', reason)) const pr = Promise.race([p1, p3, p2]) //const pr = Promise.race([p2, p3, p1]) pr.then( value => console.log('pr race onResolved()', value), reason => console.log('pr race onRejected()', reason), )

深入Promise

  1. 如何改变promise的状态? (1)resolve(value): 如果当前是pendding就会变为resolved (2)reject(reason): 如果当前是pendding就会变为rejected (3)抛出异常: 如果当前是pendding就会变为rejected

  2. 一个promise指定多个成功/失败回调函数, 当promise改变为对应状态时都会调用

          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
const p = new Promise((resolve, reject) => { // resolve(1) // pending ==> resolved // reject(2) // pending ==> rejected // throw 3 // 执行器中抛出异常 pending ==> rejected }) p.then( value => console.log('onResolved()', value), reason => console.log('onRejected()', reason) ) p.then( value => console.log('onResolved2()', value), reason => console.log('onRejected2()', reason) ) console.log(p)
  1. 改变promise状态和指定回调函数谁先谁后? (1)都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调 (2)如何先改状态再指定回调? 在执行器中直接调用resolve()/reject() 延迟更长时间才调用then() (3)什么时候才能得到数据? ①如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据 ②如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据
          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
const p = new Promise((resolve, reject) => { // 同步回调 console.log('excutor()') // 启动异步任务 setTimeout(() => { resolve(1) // pending ==> resolved value为1 console.log('resolve()改变状态后') // reject() }, 1000) }) setTimeout(() => { p.then( // 先指定回调函数, 内部选将回调函数保存起来 value => { // 成功/失败的回调函数是异步执行的, 需要放入队列将来执行 console.log('onResolved()', value) } ) },5000); console.log('new Promise()之后')
          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
const p = new Promise((resolve, reject) => { // 同步回调 console.log('excutor()') // 启动异步任务 setTimeout(() => { resolve(1) // pending ==> resolved value为1 console.log('resolve()改变状态后') // reject() }, 5000) }) setTimeout(() => { p.then( // 先指定回调函数, 内部选将回调函数保存起来 value => { // 成功/失败的回调函数是异步执行的, 需要放入队列将来执行 console.log('onResolved()', value) } ) },1000); console.log('new Promise()之后')
  1. promise的then()返回一个新的promise, 可以开成then()的链式调用,通过then的链式调用串连多个同步/异步任务
          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
new Promise((resolve, reject) => { // 启动任务1(异步) console.log('启动任务1(异步)') setTimeout(() => { resolve(1) }, 1000) }).then(value => { console.log('任务1成功的value为', value) // 执行任务2(同步) console.log('执行任务2(同步)') return 2 }).then(value => { console.log('任务2成功的vlaue为', value) // 执行任务3(异步) return new Promise((resolve, reject) => { console.log('调动任务3(异步)') setTimeout(() => { resolve(3) }, 1000); }) }).then(value => { console.log('任务3成功的value为: ', value) })
  1. 中断promise链 (1)当使用promise的then链式调用时, 在中间中断, 不再调用后面的回调函数 (2)办法: 在回调函数中返回一个pendding状态的promise对象
          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
new Promise((resolve, reject) => { // resolve(1) reject(2) }).then( value => console.log('onResolved1()', value), // reason => {throw reason} ).then( value => console.log('onResolved2()', value), // reason => Promise.reject(reason) ).then( value => console.log('onResolved3()', value), // reason => {throw reason} ).catch(reason => { console.log('onRejected1()', reason) // throw reason return new Promise(() => {}) // 返回一个pending状态的promise ==> 中断promise链接 }).then( value => console.log('onResolved4()', value), reason => console.log('onRejected2()', reason) )

async与await

  1. async 函数 函数的返回值为promise对象 promise对象的结果由async函数执行的返回值决定

  2. await 表达式 await右侧的表达式一般为promise对象, 但也可以是其它的值 如果表达式是promise对象, await返回的是promise成功的值 如果表达式是其它值, 直接将此值作为await的返回值

  3. 注意: await必须写在async函数中, 但async函数中可以没有await 如果await的promise失败了, 就会抛出异常, 需要通过try...catch来捕获处理 为什么用async和await 简化promise对象的使用, 不用再通过then指定回调函数取结果数据 回调地狱的终极解决方案

          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
// async函数的返回值为promise对象 async function fn1() { // return 1 // throw 2 // return Promise.reject(3) return Promise.resolve(4) } const result = fn1() console.log(result) function fn3() { // return 3 // return Promise.resolve(5) return new Promise((resolve, reject) => { setTimeout(() => { resolve(6) }, 2000); }) } // async函数会立即执行结束返回一个pending状态的promise对象 async function fn2() { // await后面的代码会放入then()的成功回调中执行的 const result = await fn3() console.log(result) } // fn2() // console.log('fn2()之后') // 与async + await的效果是一样的 function fn4() { return fn3().then(result => { console.log(result) }) } // fn4() // console.log('fn4()之后') async function fn5() { throw 6 } async function fn6() { try { // 使用try...catch来处理await后的promise的失败 const result = await fn5() console.log('fn6 result=', result) } catch (error) { console.log('error', error) } } fn6()

看看输出什么?

          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
async function async1() { console.log('async1 start') await async2() // async2().then(() => {}) console.log('async1 end') } async function async2() { console.log('async2') } console.log('script start') setTimeout(() => { console.log('setTimeout') }, 0) async1() new Promise(function (resolve) { console.log('promise1') resolve() }).then(function () { console.log('promise2') }) console.log('script end')

宏队列与微队列

在准备取出每个宏任务准备执行前要执行完所有的微任务

Snipaste_20200513_124859.jpg

宏队列与微队列理解

          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
setTimeout(() => { console.log('setTimeout callback()', 1) Promise.resolve(5).then(value => { console.log('onResolved3()', value) }) }, 0) setTimeout(() => { console.log('setTimeout callback()', 2) }, 0) Promise.resolve(3).then(value => { console.log('onResolved()', value) }) Promise.resolve(4).then(value => { console.log('onResolved2()', value) }) // 3 5 4 1 2
          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
setTimeout(() => { console.log(1) }, 0) Promise.resolve().then(() => { console.log(2) }) Promise.resolve().then(() => { console.log(4) }) console.log(3) // 3 2 4 1
          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
setTimeout(() => { console.log(1) }, 0) new Promise((resolve) => { console.log(2) resolve() }).then(() => { console.log(3) }).then(() => { console.log(4) }) console.log(5) // 2 5 3 4 1
          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
const first = () => (new Promise((resolve, reject) => { console.log(3) let p = new Promise((resolve, reject) => { console.log(7) setTimeout(() => { console.log(5) resolve(6) }, 0) resolve(1) }) resolve(2) p.then((arg) => { console.log(arg) }) })) first().then((arg) => { console.log(arg) }) console.log(4) //3 7 4 1 2 5
          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
setTimeout(() => { console.log("0") }, 0) new Promise((resolve, reject) => { console.log("1") resolve() }).then(() => { console.log("2") new Promise((resolve, reject) => { console.log("3") resolve() }).then(() => { console.log("4") }).then(() => { console.log("5") }) }).then(() => { console.log("6") }) new Promise((resolve, reject) => { console.log("7") resolve() }).then(() => { console.log("8") }) //1 7 2 3 8 4 6 5 0
---End---
(完)
浅拷贝深拷贝
前端基本技能,面试必备
谈谈公司和工作
纯吐槽,不宜观看
青岛四天三夜
很美丽,很适合居住的一座城市
React Refs的使用
Refs 提供了一种方式,允许我们访问 DOM 节点或在 render 方法中创建的 React 元素。
杂谈
想做款副业
人性的弱点
戴尔·卡耐基
等待你的评论