什么是Promise?
Promise
是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一。
从语法上来说:Promise是一个构造函数。
从功能上来说:promise对象是用来封装一个异步操作并可以获取其结果。
Promises/A+ 规范
为实现者提供一个健全的、可互操作的 JavaScript promise
的开放标准。
相关术语
解决 (fulfill)
: 指一个 promise 成功时进行的一系列操作,如状态的改变、回调的执行。虽然规范中用 fulfill 来表示解决,但在后世的 promise 实现多以 resolve
来指代之。
拒绝(reject)
: 指一个 promise 失败时进行的一系列操作。
拒因 (reason)
: 也就是拒绝原因,指在 promise 被拒绝时传递给拒绝回调的值。
终值(eventual value)
: 所谓终值,指的是 promise 被解决时传递给解决回调的值,由于 promise 有一次性的特征,因此当这个值被传递时,标志着 promise 等待态的结束,故称之终值,有时也直接简称为值(value)。
Promise
: promise 是一个拥有 then 方法的对象或函数,其行为符合本规范。
thenable
: 是一个定义了 then 方法的对象或函数。
异常(exception)
: 是使用 throw 语句抛出的一个值。
Promise使用
Promise状态
一个Promise的当前状态必须是以下三种状态中的一种: 等待状态(Pending)、** 执行状态(Fulfilled)** 和 拒绝状态(Rejected)。
一旦状态改变就不能再次改变。
语法
1
| new Promise( function(resolve, reject) {...} );
|
Promise接收一个参数executor
,executor是带有 resolve
和 reject
两个参数的函数 。Promise构造函数执行时立即调用
executor 函数, resolve 和 reject 两个函数作为参数传递给executor(executor 函数在Promise构造函数返回所建promise实例对象前被调用)。resolve 和 reject 函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败)。
相关流程如下图:
1 2 3 4
| const promise = new Promise((resolve, reject) => { });
|
then方法
一个 promise 必须提供一个 then 方法以访问其当前值、终值和据因,只有状态改变为Fulfilled
或者Rejected
时才会调用then
方法,如果状态为Pending
则不调用。
promise 的 then 方法接受两个参数:
1
| promise.then(onFulfilled, onRejected)
|
onFulfilled 和 onRejected 都是可选参数;如果 onFulfilled 不是函数,其必须被忽略;如果 onRejected 不是函数,其必须被忽略。
then 方法可以被同一个 promise 调用多次,then方法必须返回一个promise对象。
race方法
Promise.race(iterable)
方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。
all方法
Promise.all(iterable)
方法返回一个 Promise 实例,此实例在 iterable 参数内所有的 promise 都“完成(resolved)”或参数中不包含 promise 时回调完成(resolve);如果参数中 promise 有一个失败(rejected),此实例回调失败(reject),失败的原因是第一个失败 promise 的结果。
reject方法
Promise.reject()
方法返回一个带有拒绝原因的Promise对象。
resolve方法
Promise.resolve(value)
方法返回一个以给定值解析后的Promise 对象。如果这个值是一个 promise ,那么将返回这个 promise ;如果这个值是thenable(即带有”then” 方法),返回的promise会“跟随”这个thenable的对象,采用它的最终状态;否则返回的promise将以此值完成。此函数将类promise对象的多层嵌套展平。
手写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 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
| (function(){ const PENDING = 'pending' const RESOLVED = 'resolved' const REJECTED = 'rejected' function MyPromise(excutor){ const self = this self.status = PENDING self.data = undefined self.callbacks = [] function resolve(value){ if(self.status !== PENDING){ return } self.status = RESOLVED self.data = value if(self.callbacks.length > 0){ setTimeout(()=>{ self.callbacks.forEach(item=>{ item.onResolved(value) }) }) } } function reject(reason){ if(self.status !== PENDING){ return } self.status = REJECTED self.data = reason if(self.callbacks.length > 0){ setTimeout(()=>{ self.callbacks.forEach(item=>{ item.onRejected(reason) }) }) } } try{ excutor(resolve,reject) }catch(error){ reject(error) } } MyPromise.prototype.then = function(onResolved,onRejected){ onResolved = typeof onResolved === 'function' ?onResolved : value => value, onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason } const self = this return new MyPromise((resolve,reject)=>{ function handle(callback){ try{ const result = callback(self.data) if(result instanceof MyPromise){ result.then(resolve,reject) }else{ resolve(result) } }catch(error){ reject(error) } } if(self.status === PENDING){ self.callbacks.push({ onResolved(value){ handle(value) }, onRejected(reason){ handle(reason) } }) }else if(self.status === RESOLVED){ setTimeout(()=>{ handle(onResolved) }) }else{ setTimeout(()=>{ handle(onRejected) }) } }) } MyPromise.prototype.catch = function(onRejected){ return this.then(undefined, onRejected) } MyPromise.resolve = function(value){ return new MyPromise((resolve,reject)=>{ if(result instanceof MyPromise){ result.then(resolve,reject) }else{ resolve(result) } }) } MyPromise.reject = function(reason){ return new MyPromise((resolve,reject)=>{ reject(reason) }) } MyPromise.all = function(promises){ const values = new Array(promises.length) let resolvedCount = 0 return new MyPromise((resolve,reject)=>{ promises.forEach((item,index)=>{ MyPromise.resolve(item).then( value=>{ reslovedCount++ values[index] = value if(reslovedCount === promises.length){ resolve(values) } }, reason=>{ reject(reason) } ) }) }) } MyPromise.race = function(promises){ return new MyPromise((resolve,reject)=>{ promises.forEach((item,index)=>{ MyPromise.resolve(item).then( value=>{ resolve(value) }, reason=>{ reject(reason) } ) }) }) } window.MyPromise = MyPromise })()
var p = new MyPromise((resolve,reject)=>{ resolve(1) })
|