写在前面
以下所述内容大部分为本人在 MDN-Promise,ES6 标准入门(第二版)192 页开始,和一些博客介绍的消化咀嚼产出,带着粗浅的认识和个人主观偏向,可能理解的不是很到位,想看具体讲解的点下面传送门
Promise 是什么
按照官方的话来说,Promise 是异步编程的一种解决方案,里面通常保存着异步操作事件的结果。以前用嵌套的回调函数解决异步(产生回调地狱),现在用 Promise。
所以 promise 是用来
- 解决异步的问题
- 可以并发多个请求,获取并发请求中的数据
Promise 有什么
- 有三种状态:Pending(进行中)、Resolved(成功,又称 Fulfilled)和 Rejected(失败),只有两种变化情况,由 Pending 变为 Resolved 或 Rejected。这些状态只由操作的结果决定,状态一旦发生了改变,就会一直保持,后续回调无法改变。
- 有各种内置方法:reject,resolve,then,catch,all,race。
Promise 怎么用
基本使用:
1 2 3 4 5 6 7
| var promise = new Promise(function(resolve, reject) { if ( ) { resolve(value); } else { reject(error); } });
|
Promise 构造函数接收一个函数作为参数,该函数的两个参数分别是 resolve 和 reject。resolve 为成功状态,并返回操作结果,reject 为失败,且返回错误报告。
Promise 实例生成后,可以用then方法(在 Promise 原型对象内置有),接收两个参数,分别指定 Resolved 状态和 Reject 状态的回调函数。成功 value,失败为 reason 或 error。
1 2 3 4 5 6 7 8
| promise.then( function (value) { }, function (error) { } )
|
完整示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function doDelay(time){ return new Promise((resolve,reject) => { setTimeout(() => { if(){ resolve("xxx") } else{ reject("xxx") } }),time }) } doDelay(200).then(value => {
},reason => {
})
|
简直不要太简单,下面简单说下 Promise 其他方法
- Promise.prorotype.catch() 方法:失败的回调函数,用来指定 reject 的回调,即使上面 resolve 报错了,也能执行到 catch。
说明:是 then 的语法糖,相当于:then(undefined,onRejected)
- Promise.all 方法:接收一个包含 n 个 promise 的数组
说明:返回一个新的 promise,只有所有的 promise 都成功才成功,只要有一个失败则直接失败且第一个失败的实例作为返回值,一般用在一次加载很多请求,全加载成功在渲染。
- Promise.race 方法:跟 all 一样,接收一个包含 n 个 promise 的数组,只要有一个实例改变状态,该实例就作为返回值返回
说明:返回一个新的 promise,第一个完成的 promise 的结果状态就是最终的结果状态
- Promise.allSettled() :all 的改进版,跟 all 一样,但是等入参的 promise 状态都发生了变更才返回,返回一个包含他们状态的 Promise。
- finally() :不接收参数,不管 Promimse 对象最后状态是什么,都会执行的操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| myPromise().then( function (value) { console.log('resolved') }, function (err, data) { console.log('rejected') } )
myPromise() .then(function (data) { console.log('resolved') }) .catch(function (reason) { console.log('rejected') })
myPromise() .all([runAsync1(), runAsync2(), runAsync3()]) .then(function (results) { console.log(results) })
|
为什么要用 Promise
- 指定回调函数方式更加灵活
- 支持链式调用,不阻塞 Promise 相关的任何程序,且保持异步关系来解决回调地狱问题
Promise 在 ajax 中的应用(封装)
发送 ajax 请求的四个步骤
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () { if (xhr.readyState !== 4) return if (xhr.status === 200) { console.log(xhr.responseText) } else { new Error(xhr.statusText) } }
xhr.open('GET', url, true)
xhr.send()
|
开发中一般使用 promise 对 ajax 进行一个异步封装,具体如下:
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
| function ajax(method, url, data) { var xhr = new XMLHttpRequest() return new Promise(function (resolve, reject) { xhr.onreadystatechange = function () { if (xhr.readyState !== 4) return if (xhr.status === 200) { resolve(xhr.responseText) } else { reject(xhr.statusText) } } xhr.open(method, url) xhr.send(data) }) }
ajax('GET', '/api/xxx') .then(function (data) { console.log(data) }) .catch(function (status) { new Error(status) })
|
对该技术有更深的认识后,在更…
贴个大佬的手写源码
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 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
| function Promise(executor) { this.PromiseState = 'pending' this.PromiseResult = null this.callbacks = [] const self = this function resolve(data) { if (self.PromiseState !== 'pending') return self.PromiseState = 'fulfilled' self.PromiseResult = data self.callbacks.forEach((item) => { item.onresolved(data) }) } function reject(data) { if (self.PromiseState !== 'pending') return self.PromiseState = 'rejected' self.PromiseResult = data self.callbacks.forEach((item) => { item.onrejected(data) }) } try { executor(resolve, reject) } catch (error) { reject(error) } }
Promise.prototype.then = function (onresolved, onrejected) { const self = this if (typeof onresolved !== 'function') { onresolved = (value) => value } if (typeof onrejected !== 'function') { onrejected = (reason) => { throw reason } } return new Promise((resolve, reject) => { function callback(type) { try { let result = type(self.PromiseResult) if (result instanceof Promise) { result.then( (v) => { resolve(v) }, (r) => { reject(r) } ) } else { resolve(result) } } catch (error) { reject(error) } } if (this.PromiseState === 'fulfilled') { setTimeout(() => { callback(onresolved) }) } if (this.PromiseState === 'rejected') { setTimeout(() => { callback(onrejected) }) } if (this.PromiseState === 'pending') { this.callbacks.push({ onresolved: function () { callback(onresolved) }, onrejected: function () { callback(onrejected) }, }) } }) }
Promise.prototype.catch = function (onrejected) { return this.then(undefined, onrejected) }
Promise.resolve = function (value) { return new Promise((resolve, reject) => { if (value instanceof Promise) { value.then( (v) => { resolve(v) }, (r) => { reject(r) } ) } else { resolve(value) } }) }
Promise.reject = function (reason) { return new Promise((resolve, reject) => { reject(reason) }) }
Promise.all = function (promises) { return new Promise((resolve, reject) => { let count = 0 let arr = [] for (let i = 0; i < promises.length; i++) { promises[i].then( (v) => { count++ arr[i] = v if (count == promises.length) { resolve(arr) } }, (r) => { reject(r) } ) } }) }
Promise.race = function (promises) { return new Promise((resolve, reject) => { for (let i = 0; i < promises.length; i++) { promises[i].then( (v) => { resolve(v) }, (r) => { reject(r) } ) } }) }
|