源码
- Promise的三种状态常量 —— pending:等待态; resolved:成功态; rejected:失败态
- 链式调用的本质 —— promise的then方法必须返回一个新的promise对象
链式调用的本质:
promise2 = promise1.then(onFulfilled, onRejected)
promise1.then(onFulfilled1, onRejected1).then(onFulfilled2, onRejected2)
复制代码
源码(promise.js):
function Promise (executor) { // 构造函数Promise必须接受一个函数(executor)作为参数
this.status = 'pending' // 初始状态为pending
this.value = undefined // 成功的值
this.reason = undefined // 失败的原因
this.onResolvedCallbacks = [] // 保存成功回调函数队列(new Promise()时可能会有异步操作),见[案例4]
this.onRejectedCallbacks = [] // 保存失败回调函数队列(new Promise()时可能会有异步操作)
resolve = value => { // resovle时的执行函数(把状态变成resolved)
if (this.status === 'pending') { // 只有等待态 可以改变状态
this.value = value
this.status = 'resolved'
this.onResolvedCallbacks.forEach(fn => fn()) // 异步执行resolve()时,做【发布】操作,见[案例4]
}
}
reject = reason => { // reject时的执行函数(把状态变成rejected)
if (this.status === 'pending') { // 只有等待态 可以改变状态
this.reason = reason
this.status = 'rejected'
this.onRejectedCallbacks.forEach(fn => fn()) // 异步执行reject()时,做【发布】操作
}
}
try { // new Promise()时, 直接执行executor函数(同步执行)
executor(resolve, reject) // executor函数包含resolve和reject两个参数(且都为函数)
} catch (err) { // 如果执行exectuor时出错,就让当前promise变成失败态
reject(err)
}
}
/**
* @param {*} promise2 调用then时返回的【新的】promise对象
* @param {*} x 【当前】then中onFulfilled或onRejected函数的返回值
* 若x不为Promise,则x直接作为Promise2的值(即新的onFulfilled或onRejected函数的参数)
* 若x 为 Promise,则promise2的一个回调函数(resolve或reject),会等待该Promise对象(即x)状态变化后才会被调用,且Promise2的状态和x的状态相同
* @param {*} resolve promise2的resolve
* @param {*} reject promise2的reject
*/
function resolvePromise (promise2, x, resolve, reject) {
if (promise2 === x) { // 不能自己等自己,见[案例1]
return reject(new TypeError('Chaining cycle detected for promise'))
}
let called = false // 防止多次调用(既调成功也调失败),别人的代码可能没有判断 —— 只有等待态 可以改变状态
if (x !== null && (typeof x === 'object' || typeof x === 'function')) { //【1+】x是对象或函数才有可能是promise
try { // 尝试取x的then属性,进一步判别x是否为promise,可能会抛异常(这个promise可能是别人乱写的),见[案例5]
let t = x.then
if (typeof t === 'function') { //【2+】x.then为函数才可能是promise
/**
* x可能是promise,直接让x.then执行
* 1、promise.then() // this指向promise
* 2、let t = promise.then
* t() // this指向全局,通过t.call(x, ...)将this指向x
*
* 以下相当于:
* x.then(y => {}, err => {})
*/
t.call(x, y => { // promise成功的结果,见[案例7]
if (called) return // 防止多次调用(既调成功也调失败),别人的代码可能没有判断 —— 只有等待态 可以改变状态
called = true
resolvePromise(promise2, y, resolve, reject) // 成功的结果可能是promise,需要【递归】解析,直到解析成普通值为止
}, err => { // promise失败的结果,见[案例6]
if (called) return
called = true
reject(err)
})
} else { //【2-】x不为promise(即为普通值,如:x为{then: {}})
resolve(x)
}
} catch (err) {
if (called) return
called = true
reject(err)
}
} else { //【1-】x不为promise(即为普通值)
resolve(x)
}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
/**
* onFulfilled和onRejected是可选参数,如果onFulfilled或onRejected不是函数,必须被忽略
* 如果onFulfilled不是函数且promise为成功态,则promise2为成功态并返回promise成功的值,见[案例3]
* 如果onRejected 不是函数且promise为失败态,则promise2为失败态并返回promise失败的值
*/
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }
let promise2 = new Promise((resolve, reject) => { // 每次调用then时必须返回一个新的promise对象
switch (this.status) { // this指向promise
case 'resolved':
setTimeout(() => {
try { // 如果onFulfilled或onRejected抛出异常,则promise2必须变为失败态,见[案例2]
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (err) {
reject(err)
}
}, 0)
break
case 'rejected':
setTimeout(() => {
try { // 如果onFulfilled或onRejected抛出异常,则promise2必须变为失败态
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (err) {
reject(err)
}
}, 0)
break
case 'pending':
this.onResolvedCallbacks.push(() => { // 异步执行resolve()时,做【订阅】操作,见[案例4]
setTimeout(() => {
try { // 如果onFulfilled或onRejected抛出异常,则promise2必须变为失败态
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (err) {
reject(err)
}
}, 0)
})
this.onRejectedCallbacks.push(() => { // 异步执行reject()时,做【订阅】操作
setTimeout(() => {
try { // 如果onFulfilled或onRejected抛出异常,则promise2必须变为失败态
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (err) {
reject(err)
}
}, 0)
})
break
}
})
return promise2
}
复制代码
测试代码:
Promise.defer = Promise.deferred = function () {
let dfd = {}
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve
dfd.reject = reject
})
return dfd
}
module.exports = Promise
// npm install promises-aplus-tests -g
// promises-aplus-tests promise.js
复制代码
案例1:promise2和onFulfilled或onRejected函数返回的结果是同一个对象
let promise = new Promise((resolve, reject) => {
resolve()
})
let promise2 = promise.then(res => { // 不能自己等自己
return promise2
})
// TypeError: Chaining cycle detected for promise
复制代码
案例2:如果onFulfilled或onRejected抛出异常,则promise2必须变为失败态
let promise = new Promise((resolve, reject) => {
resolve()
})
promise2 = promise.then(res => {
throw new Error('这里抛出一个异常')
})
promise2.then(res => {
console.log(res)
}, err => {
console.log(err) // 这里抛出一个异常
})
复制代码
案例3:如果onFulfilled不是函数且promise为成功态,则promise2为成功态并返回promise成功的值
let promise = new Promise((resolve, reject) => {
resolve('success')
})
promise2 = promise.then('这里的onFulfilled本来是一个函数,但现在不是')
promise2.then(res => {
console.log(res) // success
}, err => {
console.log(err)
})
复制代码
案例4:异步执行resolve()时,做【发布、订阅】操作
非异步:
let promise = new Promise((resolve, reject) => {
resolve('成功') // 非异步执行
})
promise.then(res => { // 状态为resolved,值为成功,直接执行
console.log(res) // 成功
})
异步:
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功') // 异步执行
}, 1000)
})
promise.then(res => { // 状态为pending,值为undefined,执行【订阅】操作;1s后状态为resolved,值为成功,执行【发布】操作
console.log(res) // 1s后,成功
})
复制代码
案例5:尝试取x的then属性,进一步判别x是否为promise时,可能会抛异常
let obj = {}
Object.defineProperty(obj, 'then', {
get () {
throw new Error('出错')
}
})
console.log(obj.then) // 出错
复制代码
案例6:x.then失败
let promise = new Promise((resolve, reject) => {
resolve()
})
let promise2 = promise.then(res => {
return new Promise((resolve, reject) => {
reject('失败')
})
})
promise2.then(res => {
console.log(res)
}, err => {
console.log(err) // 失败
})
复制代码
案例7:x.then成功
let promise = new Promise((resolve, reject) => {
resolve()
})
let promise2 = promise.then(res => {
return new Promise((resolve, reject) => {
resolve(new Promise((resolve, reject) => {
resolve('成功')
}))
})
})
promise2.then(res => {
console.log(res) // 成功
}, err => {
console.log(err)
})
复制代码
应用
let fs = require('fs')
function read (filePath, encoding) {
return new Promise((resolve,reject) => {
fs.readFile(filePath, encoding, (err, data) => {
if(err) reject(err)
resolve(data)
})
})
}
read('1.txt', 'utf8').then(res => {
return read(res, 'utf8')
}).then(res => {
return read(res, 'utf8')
}).then(res => {
console.log(res) // hello
})
// 1.txt内容 2.txt
// 2.txt内容 3.txt
// 3.txt内容 hello
复制代码