基本使用

  1. // Promise 基本示例
  2. const promise = new Promise(function (resolve, reject) {
  3. // 这里用于“兑现”承诺
  4. resolve(100) // 承诺达成
  5. // reject(new Error('promise rejected')) // 承诺失败
  6. })
  7. promise.then(function (value) {
  8. // 即便没有异步操作,then 方法中传入的回调仍然会被放入队列,等待下一轮执行
  9. console.log('resolved', value)
  10. }, function (error) {
  11. console.log('rejected', error)
  12. })
  13. console.log('end')

封装ajax

  1. // Promise 方式的 AJAX
  2. function ajax (url) {
  3. return new Promise(function (resolve, reject) {
  4. var xhr = new XMLHttpRequest()
  5. xhr.open('GET', url)
  6. xhr.responseType = 'json'
  7. xhr.onload = function () {
  8. if (this.status === 200) {
  9. resolve(this.response)
  10. } else {
  11. reject(new Error(this.statusText))
  12. }
  13. }
  14. xhr.send()
  15. })
  16. }
  17. ajax('/api/urls.json').then(function (res) {
  18. console.log(res)
  19. }, function (error) {
  20. console.log(error)
  21. })

链式调用

then方法是promise对象状态明确后的回调,他会返回一个新的promise。

  • 如果在then方法中手动返回了一个promise对象,那么下一个then就是这个promise对象状态明确后的回调
  • 如果在then方法中手动返回了一个值,这个值会被下一个then当做promise返回的值接收(即便返回的这个值是throw的error也会进入onResolved回调,error成为value)
  • 如果在then方法中没有返回,那么下一个then就会收到一个undefined ```javascript // Promise 链式调用

function ajax(url) { return new Promise(function (resolve, reject) { var xhr = new XMLHttpRequest() xhr.open(‘GET’, url) xhr.responseType = ‘json’ xhr.onload = function () { if (this.status === 200) { resolve(this.response) } else { reject(new Error(this.statusText)) } } xhr.send() }) }

// var promise = ajax(‘/api/users.json’)

// var promise2 = promise.then( // function onFulfilled (value) { // console.log(‘onFulfilled’, value) // }, // function onRejected (error) { // console.log(‘onRejected’, error) // } // )

// console.log(promise2 === promise) // false

/ NOTE then方法是promise对象状态明确后的回调,他会返回一个新的promise 如果在then方法中手动返回了一个promise对象,那么下一个then就是这个promise对象状态明确后的回调 如果在then方法中手动返回了一个值,这个值会被下一个then当做promise返回的值接收(即便这个值是throw的error也会进入onResolved回调,error成为value) 如果在then方法中没有返回,那么下一个then就会收到一个undefined / ajax(‘/api/users.json’) .then(function (value) { console.log(1111) console.log(value) return ajax(‘/api/urls.json’) }) // => Promise .then(function (value) { console.log(2222) console.log(value) return ‘foo’ }) // => Promise .then(function (value) { console.log(3333) console.log(value) return new Error(‘error’) }) // => Promise .then(function (value) { console.log(4444) console.log(value) }) // => Promise .then(function (value) { console.log(5555) console.log(value) // return setTimeout(function () { // console.log(‘异步’) // }, 1000) return new Promise((resolve,reject)=>{ setTimeout(function () { console.log(‘异步’) resolve(‘异步’) }, 1000) }) }).then(function (value) { console.log(6666) console.log(value) }).catch(e => { console.log(e) })

/ 1111 [{age: 24,name: “zce”},{age: 25,name: “alan”}] 2222 {users: “/api/users.json”, posts: “/api/posts.json”} 3333 foo 4444 Error: error 5555 undefined /

  1. <a name="r99Zh"></a>
  2. ## 异常处理
  3. <a name="uVfXw"></a>
  4. ### 使用 onRejected 注册失败回调
  5. then中注册的onRejected回调只是给当前 Promise 对象注册的失败回调,只能捕获当前promise的异常<br />then(onRejected) 实际上就相当于 then(undefined, onRejected)
  6. ```javascript
  7. function ajax(url) {
  8. return new Promise(function (resolve, reject) {
  9. var xhr = new XMLHttpRequest()
  10. xhr.open('GET', url)
  11. xhr.responseType = 'json'
  12. xhr.onload = function () {
  13. if (this.status === 200) {
  14. resolve(this.response)
  15. } else {
  16. reject(new Error(this.statusText))
  17. }
  18. }
  19. xhr.send()
  20. })
  21. }
  22. ajax('/api/users11.json')
  23. .then(function onFulfilled(value) {
  24. console.log('onFulfilled', value)
  25. }, function onRejected(error) {
  26. console.log('onRejected', error)
  27. })

使用 catch 注册失败回调

使用 catch 注册失败回调是更常见的(这里的catch并不是try catch中的catch!)
因为 Promise 链条上的任何一个异常都会被一直向后传递,直至被捕获,分开注册的 onRejected 相当于给整个 Promise 链条注册失败回调

  1. function ajax(url) {
  2. return new Promise(function (resolve, reject) {
  3. var xhr = new XMLHttpRequest()
  4. xhr.open('GET', url)
  5. xhr.responseType = 'json'
  6. xhr.onload = function () {
  7. if (this.status === 200) {
  8. resolve(this.response)
  9. } else {
  10. reject(new Error(this.statusText))
  11. }
  12. }
  13. xhr.send()
  14. })
  15. }
  16. // NOTE 使用 catch 注册失败回调是更常见的
  17. ajax('/api/users11.json')
  18. .then(function onFulfilled (value) {
  19. console.log('onFulfilled', value)
  20. })
  21. .catch(function onRejected (error) {
  22. console.log('onRejected', error)
  23. })

全局捕获 Promise 异常

我们可以在全局对象上注册一个unhandledrejection事件,用来处理那些没有被手动捕获的promise异常

  1. // window 中全局捕获 Promise 异常,类似于 window.onerror,
  2. window.addEventListener('unhandledrejection', event => {
  3. const { reason, promise } = event
  4. console.log(reason, promise)
  5. // reason => Promise 失败原因,一般是一个错误对象
  6. // promise => 出现异常的 Promise 对象
  7. event.preventDefault()
  8. }, false)
  9. // Node.js 中使用以下方式
  10. process.on('unhandledRejection', (reason, promise) => {
  11. console.log(reason, promise)
  12. // reason => Promise 失败原因,一般是一个错误对象
  13. // promise => 出现异常的 Promise 对象
  14. })

静态方法

Promise.resolve(‘foo’)

如果传入的是一个普通值,就相当于一个promise成功resolve(‘foo’)
如果传入的是一个 Promise 对象,Promise.resolve 方法原样返回
如果传入的是带有一个跟 Promise 一样的 then 方法的对象,Promise.resolve 会将这个对象作为 Promise 执行

  1. function ajax(url) {
  2. return new Promise(function (resolve, reject) {
  3. var xhr = new XMLHttpRequest()
  4. xhr.open('GET', url)
  5. xhr.responseType = 'json'
  6. xhr.onload = function () {
  7. if (this.status === 200) {
  8. resolve(this.response)
  9. } else {
  10. reject(new Error(this.statusText))
  11. }
  12. }
  13. xhr.send()
  14. })
  15. }
  16. // 如果传入的是一个普通值,就相当于下面写法
  17. Promise.resolve('foo')
  18. .then(function (value) {
  19. console.log(value)
  20. })
  21. new Promise(function (resolve, reject) {
  22. resolve('foo')
  23. })
  24. // 如果传入的是一个 Promise 对象,Promise.resolve 方法原样返回
  25. var promise = ajax('/api/users.json')
  26. var promise2 = Promise.resolve(promise)
  27. console.log(promise === promise2)//true
  28. // 如果传入的是带有一个跟 Promise 一样的 then 方法的对象,Promise.resolve 会将这个对象作为 Promise 执行
  29. Promise.resolve({
  30. then: function (onFulfilled, onRejected) {
  31. onFulfilled('foo')
  32. }
  33. })
  34. .then(function (value) {
  35. console.log(value)//'foo'
  36. })

Promise.reject(‘anything’)

传入任何值,都会作为这个 Promise 失败的理由

  1. // Promise.reject 传入任何值,都会作为这个 Promise 失败的理由
  2. Promise.reject(new Error('rejected'))
  3. .catch(function (error) {
  4. console.log(error)
  5. })
  6. Promise.reject('anything')
  7. .catch(function (error) {
  8. console.log(error)
  9. })

并行执行

Promise.all

任何一个出现异常就会进入失败回调

  1. // Promise 并行执行
  2. function ajax (url) {
  3. return new Promise(function (resolve, reject) {
  4. var xhr = new XMLHttpRequest()
  5. xhr.open('GET', url)
  6. xhr.responseType = 'json'
  7. xhr.onload = function () {
  8. if (this.status === 200) {
  9. resolve(this.response)
  10. } else {
  11. reject(new Error(this.statusText))
  12. }
  13. }
  14. xhr.send()
  15. })
  16. }
  17. // ajax('/api/users.json')
  18. // ajax('/api/posts.json')
  19. var promise = Promise.all([
  20. ajax('/api/users.json'),
  21. ajax('/api/posts1.json')
  22. ])
  23. promise.then(function (values) {
  24. console.log(values)
  25. }).catch(function (error) {
  26. console.log(error)
  27. })
  28. // 批量发送请求
  29. ajax('/api/urls.json')
  30. .then(value => {
  31. const urls = Object.values(value)
  32. const tasks = urls.map(url => ajax(url))
  33. return Promise.all(tasks)
  34. })
  35. .then(values => {
  36. console.log(values)
  37. })

Promise.race

只要有一个返回结果就更改状态进入回调

  1. // Promise.race 实现超时控制
  2. const request = ajax('/api/posts.json')
  3. const timeout = new Promise((resolve, reject) => {
  4. setTimeout(() => reject(new Error('timeout')), 500)
  5. })
  6. Promise.race([
  7. request,
  8. timeout
  9. ])
  10. .then(value => {
  11. console.log(value)
  12. })
  13. .catch(error => {
  14. console.log(error)
  15. })

执行时序

Promise 的回调是微任务,本轮调用末尾直接执行

  1. // 微任务
  2. console.log('global start')
  3. // setTimeout 的回调是 宏任务,进入回调队列排队
  4. setTimeout(() => {
  5. console.log('setTimeout')
  6. }, 0)
  7. // Promise 的回调是 微任务,本轮调用末尾直接执行
  8. Promise.resolve()
  9. .then(() => {
  10. console.log('promise')
  11. })
  12. .then(() => {
  13. console.log('promise 2')
  14. })
  15. .then(() => {
  16. console.log('promise 3')
  17. })
  18. console.log('global end')
  19. /*
  20. global start
  21. global end
  22. promise
  23. promise 2
  24. promise 3
  25. setTimeout
  26. */