Promise的使用
Promise是ES6新增的内置类
let p = new Promise(executor)
new Promise的时候,必须传递一个函数 executor ,传递的是其他类型值,则报错
Promise必须被new执行,不能作为普通函数执行
1. 实例的私有属性
+ [[PromiseState]]: "pending" 实例的状态 pending(准备) fulfilled(成功) rejected(失败)
+ [[PromiseResult]]: undefined 实例的值 undefined 成功的结果 失败的原因
2. 实例的公有属性 Promise.prototype
+ then
+ catch
+ finally
+ Symbol(Symbol.toStringTag): "Promise"
3. 把类做为普通对象,设置静态私有属性 Promise.xxx
+ all
+ any
+ race
+ resolve
+ reject
+ allSettled 返回一个 Promise,该 Promise 在所有传入的 Promise 已解决(无论成功还是失败)后解决,并返回一个包含每个 Promise 结果的数组,每个结果都有一个 status 字段,用于表示该 Promise 的状态
Promise是用来管理异步编程的,我们经常把异步代码写在 executor 函数中
如何创建实例,以及如何修改其状态和值!!!
1、基于构造函数执行来创建实例
let p = new Promise(executor)
+ 立即执行executor函数,并且把Promise内部的resolve和reject方法作为参数传递给executor
+ resolve(value) 把实例的状态改为fulfilled,并且把value作为实例的值
+ reject(reason) 把实例的状态改为rejected,并且把reason作为实例的值
+ 如果executor函数抛出异常,则实例的状态改为rejected,并且把异常作为实例的值
+ 实例的状态一旦改变为fulfilled或rejected,则不可再改变
2、基于Promise.resolve/reject方法创建实例
+ Promise.resolve(10) -> 创建一个状态为fulfilled,值是10的实例
+ Promise.reject(0) -> 创建一个状态为rejected,值是0的实例
3、每一次执行then方法,都会返回一个 "全新的" Promise实例
目的:实现 "then链" 机制
let p2 = p1.then(onFulfilled, onRejected)
+ p2 是一个全新的Promise实例
+ p2的状态和值,取决于 onFulfilled或者onRejected 中的任意一个方法执行,我们观察执行的细节和结果,来决定p2的状态和值!!!
+ 首先看方法执行是否报错;如果执行报错,则p2的状态为rejected,值是报错的原因
+ 再看方法执行的返回值,是否是单独的promise实例【别名:pp】
+ 不是:则p2是fulfilled,值就是函数的返回值
+ 是:则p2的状态和值和pp的状态和值一致
4、Promise.all/any/race([promises])
+ 都会返回一个新实例 [别名p,或者称之为总的实例]
+ p的状态和值,取决于[promises]实例集合中的,每个实例的状态和值
+ [promises]集合中如果有一项不是promise实例,则要变为:状态为成功,值是本身的实例
+ all:所有实例为成功,总实例p才是成功[值:按集合顺序依次存储每一项的值],如果有一个实例为失败,则总实例p就是失败[值是失败项的值]
+ any:兼容性较差,它是ES靠后版本(11/12)中新增的;只要有一个成功,总实例p就是成功[值是成功这一项的值],如果所有项都是失败的,则总实例p才是失败的[值:all promise were rejected]
+ race:谁先处理完成就听谁的[把最快处理完毕的结果同步给总实例p]
new Promise的时候会立即执行 executor (也就是立即处理了异步代码),然后根据异步代码的执行结果,执行onFulfilled或者onRejected方法
知道了实例的状态和值,有啥用?
1、可以调用then方法,确定成功和失败各干什么
p.then(onFulfilled, onRejected)
+ onFulfilled:在实例状态为成功的时候触发执行
+ onRejected:在实例状态为失败的时候触发执行
+ 都会把实例的值传递给这两个函数
+ 同一个实例,可多次调用then方法,最后会把每一次调用传递的onFulfilled或者onRejected都执行 也就是then链
2、then链的穿透机制和catch/finally
p.then(onFulfilled, onRejected)
+ 如果onFulfilled或者onRejected没有传递,则顺延至 "下一个then中" "同等状态" 要执行的方法
+ 原理:如果不设置对应的函数,Promise内部会默认设置一个函数,实现状态/值的顺延
p.catch(onRejected)
+ 等同于p.then(null, onRejected)
p.finally(onFinally)
+ 不论成功还是失败,都会把onFinally执行
真实项目发开中,我们使用Promise,then中一般只放onFulfilled成功做的事情,在then链的末尾,设置一个catch,处理失败的情况;根据then链的穿透机制,中间不论那个环节出现失败的案例,都会顺延至最后一个catch进行失败的统一处理
下面是Promise的一些简单实现
;(function () {
'use strict'
function Promise(execute) {
var self = this,
delayTimer = null
if (typeof execute !== 'function') throw new TypeError('Promise resolver' + execute + 'is not a function')
if (!(self instanceof Promise)) throw new TypeError('undefined is not a promise')
self.state = 'pending'
self.value = undefined
self.onFulfilledCallbacks = []
self.onRejectedCallbacks = []
var change = function change(State, Value) {
if (self.state !== 'pending') return
self.state = State
self.value = Value
delayTimer = setTimeout(function () {
clearTimeout(delayTimer)
delayTimer = null
var callbacks = self.state === 'fulfilled' ? self.onFulfilledCallbacks : self.onRejectedCallbacks,
i = 0
for (; i < callbacks.length; i++) {
callbacks[i](self.value)
}
})
}
try {
execute(
function resolve(result) {
change('fulfilled', result)
},
function reject(reason) {
change('rejected', reason)
}
)
} catch (error) {
change('rejected', error.message)
}
}
function resolvePromise(promise, x, resolve, reject) {
if (x === promise) throw new TypeError('Chaining cycle detected for promise #')
if (x !== null && /^(object|function)$/i.test(typeof x)) {
var then
try {
then = x.then
} catch (err) {
reject(err)
}
if (typeof then === 'function') {
var called = false
try {
then.call(
x,
function onfulfilled(y) {
if (called) return
called = true
resolvePromise(promise, y, resolve, reject)
},
function onrejected(r) {
if (called) return
called = true
reject(r)
}
)
} catch (err) {
if (called) return
reject(err)
}
return
}
}
resolve(x)
}
function common(callback, value, promise, resolve, reject) {
try {
var x = callback(value)
resolvePromise(promise, x, resolve, reject)
} catch (err) {
reject(err)
}
}
Promise.prototype = {
constructor: Promise,
then: function then(onfulfilled, onrejected) {
var self = this,
delayTimer = null,
promise
if (typeof onfulfilled !== 'function') {
onfulfilled = function onfulfilled(result) {
return result
}
}
if (typeof onrejected !== 'function') {
onrejected = function onrejected(reason) {
throw reason
}
}
promise = new Promise(function (resolve, reject) {
switch (self.state) {
case 'fulfilled':
setTimeout(function () {
common(onfulfilled, self.value, promise, resolve, reject)
})
break
case 'rejected':
setTimeout(function () {
common(onrejected, self.value, promise, resolve, reject)
})
break
default:
self.onFulfilledCallbacks.push(function (result) {
setTimeout(function () {
common(onfulfilled, result, promise, resolve, reject)
})
})
self.onRejectedCallbacks.push(function (reason) {
setTimeout(function () {
common(onrejected, reason, promise, resolve, reject)
})
})
}
})
return promise
},
catch: function mycatch(onrejected) {
return this.then(null, onrejected)
}
}
if (typeof Symbol !== 'undefined') Promise.prototype[Symbol.toStringTag] = 'Promise'
Promise.resolve = function resolve(result) {
return new Promise(function (resolve) {
resolve(result)
})
}
Promise.reject = function reject(_, reason) {
return new Promise(function (reject) {
reject(reason)
})
}
Promise.all = function all(promises) {
if (!Array.isArray(promises))
throw new TypeError('promises must be an Array')
;(varn = 0), (results = [])
return new Promise(function (resolve, reject) {
for (var i = 0; i < promises.length; i++) {
;(function (i) {
var promise = promises[i]
if (!isPromise(promise)) promise = Promise.resolve(promise)
promise
.then(function (result) {
n++
results[i] = result
if (n >= promises.length) resolve(results)
})
.catch(function (reason) {
reject(reason)
})
})(i)
}
})
}
Promise.deferred = function deferred() {
var result = {}
result.promise = new Promise(function (resolve, reject) {
result.resolve = resolve
result.reject = reject
})
return result
}
function isPromise(x) {
if (x !== null && /^(object|function)$/i.test(typeof x)) {
if (typeof x.then === 'function') {
return true
}
}
return false
}
if (typeof window !== 'undefined') window.Promise = Promise
if (typeof Symbol !== 'undefined') Promise.prototype[Symbol.toStringTag] = 'Promise'
})()