Promise 承诺,在异步编程中用来描述异步任务,当前不执行,承诺执行,美剧里常常是I
promise~ 挂在嘴边javascript
new Promise(..) 构造器前端
var p = new Promise( function(resolve,reject){ // 接收函数做为构造器参数 // resolve(..)用于将promise状态从pending改成fulfilled // reject(..)用于将promise状态从pending改成rejected } );
resolve(..) 既可能完成 promise,也可能拒绝,要根据传入参数而定。java
若是传给 resolve(..) 的是一个非 Promise、非 thenable 的当即值,这个 promise 就会用这个值完成。git
若是传给 resolve(..) 的是一个真正的 Promise 或 thenable 值,这个值就会被递归展开,而且(要构造的)promise 将取用其最终决议值或状态。es6
Promise.resolve 建立一个已完成的 Promisegithub
语法上二者是等同的面试
var p1 = new Promise( function(resolve,reject){ resolve( "Oops" ); } ); var p2 = Promise.resolve( "Oops" );
Promise.reject 建立一个已被拒绝的 Promise编程
var p1 = new Promise( function(resolve,reject){ reject( "Oops" ); } ); var p2 = Promise.reject( "Oops" );
输入一组promise,返回一个新的promise。只有传入的所有 promise 的状态都变为fulfilled
,返回 promise 才能改变为fulfilled
。能够理解为逻辑与(&&
)数组
输入一组promise,返回一个新的promise。只有传入的全部 promise 的状态都改变后(fulfilled
或rejected
),返回 promise 才能改变为fulfilledpromise
输入一组promise,返回一个新的promise。结果的promise与第一个 状态发生改变(fulfilled
或rejected
)promise相同
接受一组 Promise 实例做为参数,包装成一个新的 Promise 实例。只要参数实例有一个变成fulfilled
状态,包装实例就会变成fulfilled
状态;若是全部参数实例都变成rejected
状态,包装实例就会变成rejected
状态。相似于逻辑或 (||
)
若向 Promise.all([ .. ]) 传入空数组,它会当即完成,但 Promise.race([ .. ]) 会挂住,且永远不会完成。
实例方法:
then(..) 接受一个或两个参数:第一个用于完成回调,第二个用于拒绝回调。若是二者中
的任何一个被省略或者做为非函数值传入的话,就会替换为相应的默认回调。默认完成回
调只是把消息传递下去,而默认拒绝回调则只是从新抛出(传播)其接收到的出错缘由
只接受一个拒绝回调做为参数,并自动替换默认完成回调。换句话说,它等价于 then(null,..):
接收一个参数,不论promise的最终状态如何都会执行,
then(..) 和 catch(..) 也会建立并返回一个新的 promise,这个 promise 能够用于实现
Promise 链式流程控制。
若是完成或拒绝回调中抛出异常,返回的 promise 是被拒绝的。若是任意一个回调返回非 Promise、非 thenable 的当即值,这个值会被用做返回 promise 的完成值。
若是完成处理函数返回一个 promise 或 thenable,那么这个值会被展开,并做为返回promise 的决议值。
对于错误处理,通常咱们使用try…catch,可是它只能捕捉同步代码的异常。
try{ setTimeout(function () { console.log('happen',x) }) }catch (e) { console.log('exception',e) } // Uncaught ReferenceError: x is not defined
在promise中,若是发生异常,将由then()中的reject处理函数进行错误捕获。
Promise.reject(10).then((val)=>{ console.log(val) },(err)=>{ console.log('then',err) }) // then 10
Promise.resolve(10).then(function (val) { console.log(val) return Promise.reject(val) }).then(val => { console.log(val) }, err => { console.log('then', err) }) // 10 // then 10
若是忘记在then()中对异常进行捕获,将会丢失被忽略和抛弃的Promise错误。因而,实现Promise异常控制的最佳实践就是以catch()结尾来进行异常处理。
Promise.resolve(10).then(function (val) { console.log(val) return Promise.reject(val) }).then(val => { console.log(val) }).catch(err=>{ console.log('err',err) }) // err 10
可是,若是咱们在catch中发生了异常呢?
Promise.reject(10).catch(err=>{ console.log('catch',10+x) }) // ReferenceError: x is not defined Promise.reject(10).catch(err => { console.log('catch', 10 + x) }).catch(err=>{ console.log('catch2',err) }) // catch2 ReferenceError: x is not defined
其实咱们能够在调用链后面再次补充一个catch来保证捕获任何可能出现的错误。可是这样的写法不是很优雅,有种经常使用的方法是使用done(标志着promise的结尾,不会建立和返回promise,不在es6规范中),现阶段能够经过增长 polyfill
Promise.prototype.done = function (onFulfilled, onRejected) { this.then(onFulfilled, onRejected) .catch(function (err) { // 抛出一个全局错误 setTimeout(() => { throw err }, 0); }); };
在浏览器中,咱们可使用 unhandledrejection
事件来捕获这类 error:
window.addEventListener('unhandledrejection', function(event) { // 这个事件对象有两个特殊的属性: alert(event.promise); // [object Promise] - 生成该全局 error 的 promise alert(event.reason); // Error: Whoops! - 未处理的 error 对象 }); new Promise(function() { throw new Error("Whoops!"); });
若是出现了一个 error,而且在这儿没有 .catch
,那么 unhandledrejection
处理程序(handler)就会被触发,并获取具备 error 相关信息的 event
对象,因此咱们就能作一些后续处理了
如下代码的执行顺序是?
const promise=new Promise((resolve,reject)=>{ console.log(1); resolve(); console.log(2); }) promise.then(()=>{ console.log(3); }) console.log(4); // 1 // 2 // 4 // 3
new Promise
是同步执行的,因此先打印1,2console.log(4)
,接着打印 4console.log(3)
,打印出3第二段代码
const promise=Promise.resolve(1).then(2).then(Promise.resolve(3)).then(console.log);//1
过程分解
- Promise.resolve(1) 生成的promise ,返回值为1,状态为fulfilled
- then(2)中,传入了非函数,返回的promise 的值为上一步的promise的值(即为1),状态为fulfilled
- then(Promise.resolve(3)) 这一步中参数类型为promise,仍取上一步的promise的值(即为1),状态为fulfilled
- then(console.log), 这一步参数为函数,传入值1
class Promise { constructor (executor) { // 参数校检 if (typeof executor !== 'function') { throw new TypeError(`Promise resolver ${executor} is not a function`) } this.initValue() this.initBind() try { executor(this.resolve, this.reject) } catch (e) { this.reject(e) } } initValue () { // state:pending/fulfilled/rejected this.value = null//终值 this.reason = null//拒因 this.state = Promise.PENDING //用于处理异步 this.onFulfilledCallbacks = [] //成功回调 this.onRejectedCallbacks = []//失败回调 } resolve (value) { //成功后的一系列操做(状态的改变,成功回调的执行) //状态不可逆 从pending开始 if (this.state === Promise.PENDING) { this.state = Promise.FULFILLED this.value = value this.onFulfilledCallbacks.forEach(fn => fn(this.value)) } } //绑定this initBind () { this.resolve = this.resolve.bind(this) this.reject = this.reject.bind(this) } reject (reason) { //失败后的一系列操做(状态的改变,失败回调的执行) if (this.state === Promise.PENDING) { this.state = Promise.REJECTED this.reason = reason this.onRejectedCallbacks.forEach(fn => fn(this.reason)) } } catch (onRejected) { return this.then(null, onRejected) // 至关于then里的成功回调只传个null } then (onFulfilled, onRejected) { //实现链式调用且改变了后面then方法的值,必须经过新的实例 let promise2 = new Promise((resolve, reject) => { // 参数校检 if (typeof onFulfilled !== 'function') { onFulfilled = function (value) { return value } } if (typeof onRejected !== 'function') { onRejected = function (reason) { throw reason } } if (this.state === Promise.FULFILLED) { //模拟异步任务 setTimeout(() => { try { const x = onFulfilled(this.value) Promise.resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }) } if (this.state === Promise.REJECTED) { setTimeout(() => { try { const x = onRejected(this.reason) Promise.resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }) } // 处理异步 if (this.state === Promise.PENDING) { this.onFulfilledCallbacks.push((value) => { setTimeout(() => { try { const x = onFulfilled(value) Promise.resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }) }) this.onRejectedCallbacks.push(reason => { setTimeout(() => { try { const x = onRejected(reason) Promise.resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }) }) } }) return promise2 } } Promise.resolvePromise = function (promise, x, resolve, reject) { // x与promise相等时 循环引用 if (promise === x) { return reject(new TypeError('Chaining cycle detected for promise')) } // 函数调用一次的开关项 防止重复调用 let called if (x instanceof Promise) { /** * x为 Promise * 1. x 为 pending,promise需保持 pending 直至x被拒绝或执行 * 2. x 为 fulfilled 用相同的值执行promise * 3. x 为 rejected 用相同的拒因执行promise */ x.then(value => {Promise.resolvePromise(promise, value, resolve, reject)}, reason => {reject(reason)}) } else if (x && (typeof x === 'object' || typeof x === 'function')) { // x 为对象或函数 try { let then = x.then // 处理thenable if (typeof then === 'function') { then.call(x, value => { if (called) return called = true Promise.resolvePromise(promise, value, resolve, reject) }, reason => { if (called) return called = true reject(reason) }) } else { resolve(x) } } catch (e) { if (called) return called = true reject(e) } } else { resolve(x) } } Promise.resolve = function (val) { return new Promise(resolve => { resolve(val) }) } Promise.reject = function (reason) { return new Promise((resolve, reject) => { reject(reason) }) } Promise.race = function (promises) { return new Promise((resolve, reject) => { for (let i = 0; i < promises.length; i++) { promises[i].then(data => { resolve(data) }) } }) } Promise.all = function (promises) { let result = [] return new Promise((resolve, reject) => { for (let i = 0; i < promises.length; i++) { promises[i].then(value => { result.push(value) if (result.length === promises.length) { resolve(arr) } }, reject) } }) } Promise.PENDING = 'pending' Promise.FULFILLED = 'fulfilled' Promise.REJECTED = 'rejected' Promise.defer = Promise.deferred = function () { let dfd = {} dfd.promise = new Promise((resolve, reject) => { dfd.resolve = resolve dfd.reject = reject }) return dfd } module.exports = Promise