解读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
const p = new Promise((resolve, reject) => { // 1)同步执行的执行器函数
// 2) 在执行器函数中启动异步任务
setTimeout(() => {
// 3) 根据结果做不同处理
const time = Date.now()
// 3.1) 如果成功了, 调用resolve(), 指定成功的value, 变为resolved状态
if (time % 2 == 1) {
resolve('成功的数据 ' + time)
console.log('resolve()之后')
} else {// 3.2) 如果失败了, 调用reject(), 指定失败的reason, 变为rejected状态
reject('失败的数据 ' + time)
}
}, 1000);
})
// 4) 能promise指定成功或失败的回调函数来获取成功的vlaue或失败的reason
p.then(
value => {
console.log('成功', value)
},
error => {
console.log('失败', error)
}
)
Promise的API
Promise构造函数: Promise (excutor) {} excutor函数: 同步执行 (resolve, reject) => {} resolve函数: 内部定义成功时我们调用的函数 value => {} reject函数: 内部定义失败时我们调用的函数 reason => {} 说明: excutor会在Promise内部立即同步回调,异步操作在执行器中执行
Promise.prototype.then方法: (onResolved, onRejected) => {} onResolved函数: 成功的回调函数 (value) => {} onRejected函数: 失败的回调函数 (reason) => {} 说明: 指定用于得到成功value的成功回调和用于得到失败reason的失败回调 返回一个新的promise对象
Promise.prototype.catch方法: (onRejected) => {} onRejected函数: 失败的回调函数 (reason) => {} 说明: then()的语法糖, 相当于: then(undefined, onRejected)
Promise.resolve方法: (value) => {} value: 成功的数据或promise对象 说明: 返回一个成功/失败的promise对象
Promise.reject方法: (reason) => {} reason: 失败的原因 说明: 返回一个失败的promise对象
Promise.all方法: (promises) => {} promises: 包含n个promise的数组 说明: 返回一个新的promise, 只有所有的promise都成功才成功, 只要有一个失败了就直接失败
7.Promise.race方法: (promises) => {} promises: 包含n个promise的数组 说明: 返回一个新的promise, 第一个完成的promise的结果状态就是最终的结果状态
例子
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
new Promise((resolve, reject) => {
setTimeout(() => {
// resolve(1)
reject(2)
}, 1000);
}).then(value => {
console.log('onResolved()', value)
}/* , error=> {
console.log('onRejected()', error)
} */).catch(error=> {
console.log('onRejected2()', error)
})
此法来解决回调地狱
- 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
//回调地狱
doSomething(function (result) {
// 第一个异步任务成功启动第二个异步任务
doSomethingElse(result, function (newResult) {
// 第二个异步任务成功启动第三个异步任务
doThirdThing(newResult, function (finalResult) {
// 第三个异步任务成功了
console.log('Got the final result: ' + finalResult)
}, failureCallback)
}, failureCallback)
}, failureCallback)
//链式调用解决回调地狱
doSomething()
.then(function (result) {
return doSomethingElse(result)
})
.then(function (newResult) {
return doThirdThing(newResult)
})
.then(function (finalResult) {
console.log('Got the final result: ' + finalResult)
})
.catch(failureCallback)
Promise.all 全成功才行
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000);
})
const p2 = Promise.resolve(2)
const p3 = Promise.reject(3)
const p4 = Promise.reject(4)
p1.then(value => console.log('p1 value', value))
p2.then(value => console.log('p2 value', value))
p3.catch(reason => console.log('p3 value', reason))
p4.catch(reason => console.log('p4 value', reason))
const pa = Promise.all([p1, p2, p3, p4])
// const pa = Promise.all([p1, p2])
pa.then(
values => console.log('pa all onResolved()', values), // 数据的顺序与promise数组顺序一致,不是按先后
reason => console.log('pa all onRejected()', reason),
)
Promise.race 谁先取谁
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000);
})
const p2 = Promise.resolve(2)
const p3 = Promise.reject(3)
const p4 = Promise.reject(4)
p1.then(value => console.log('p1 value', value))
p2.then(value => console.log('p2 value', value))
p3.catch(reason => console.log('p3 value', reason))
p4.catch(reason => console.log('p4 value', reason))
const pr = Promise.race([p1, p3, p2])
//const pr = Promise.race([p2, p3, p1])
pr.then(
value => console.log('pr race onResolved()', value),
reason => console.log('pr race onRejected()', reason),
)
深入Promise
如何改变promise的状态? (1)resolve(value): 如果当前是pendding就会变为resolved (2)reject(reason): 如果当前是pendding就会变为rejected (3)抛出异常: 如果当前是pendding就会变为rejected
一个promise指定多个成功/失败回调函数, 当promise改变为对应状态时都会调用
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
const p = new Promise((resolve, reject) => {
// resolve(1) // pending ==> resolved
// reject(2) // pending ==> rejected
// throw 3 // 执行器中抛出异常 pending ==> rejected
})
p.then(
value => console.log('onResolved()', value),
reason => console.log('onRejected()', reason)
)
p.then(
value => console.log('onResolved2()', value),
reason => console.log('onRejected2()', reason)
)
console.log(p)
- 改变promise状态和指定回调函数谁先谁后? (1)都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调 (2)如何先改状态再指定回调? 在执行器中直接调用resolve()/reject() 延迟更长时间才调用then() (3)什么时候才能得到数据? ①如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据 ②如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
const p = new Promise((resolve, reject) => { // 同步回调
console.log('excutor()')
// 启动异步任务
setTimeout(() => {
resolve(1) // pending ==> resolved value为1
console.log('resolve()改变状态后')
// reject()
}, 1000)
})
setTimeout(() => {
p.then( // 先指定回调函数, 内部选将回调函数保存起来
value => { // 成功/失败的回调函数是异步执行的, 需要放入队列将来执行
console.log('onResolved()', value)
}
)
},5000);
console.log('new Promise()之后')
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
const p = new Promise((resolve, reject) => { // 同步回调
console.log('excutor()')
// 启动异步任务
setTimeout(() => {
resolve(1) // pending ==> resolved value为1
console.log('resolve()改变状态后')
// reject()
}, 5000)
})
setTimeout(() => {
p.then( // 先指定回调函数, 内部选将回调函数保存起来
value => { // 成功/失败的回调函数是异步执行的, 需要放入队列将来执行
console.log('onResolved()', value)
}
)
},1000);
console.log('new Promise()之后')
- promise的then()返回一个新的promise, 可以开成then()的链式调用,通过then的链式调用串连多个同步/异步任务
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
new Promise((resolve, reject) => {
// 启动任务1(异步)
console.log('启动任务1(异步)')
setTimeout(() => {
resolve(1)
}, 1000)
}).then(value => {
console.log('任务1成功的value为', value)
// 执行任务2(同步)
console.log('执行任务2(同步)')
return 2
}).then(value => {
console.log('任务2成功的vlaue为', value)
// 执行任务3(异步)
return new Promise((resolve, reject) => {
console.log('调动任务3(异步)')
setTimeout(() => {
resolve(3)
}, 1000);
})
}).then(value => {
console.log('任务3成功的value为: ', value)
})
- 中断promise链 (1)当使用promise的then链式调用时, 在中间中断, 不再调用后面的回调函数 (2)办法: 在回调函数中返回一个pendding状态的promise对象
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
new Promise((resolve, reject) => {
// resolve(1)
reject(2)
}).then(
value => console.log('onResolved1()', value),
// reason => {throw reason}
).then(
value => console.log('onResolved2()', value),
// reason => Promise.reject(reason)
).then(
value => console.log('onResolved3()', value),
// reason => {throw reason}
).catch(reason => {
console.log('onRejected1()', reason)
// throw reason
return new Promise(() => {}) // 返回一个pending状态的promise ==> 中断promise链接
}).then(
value => console.log('onResolved4()', value),
reason => console.log('onRejected2()', reason)
)
async与await
async 函数 函数的返回值为promise对象 promise对象的结果由async函数执行的返回值决定
await 表达式 await右侧的表达式一般为promise对象, 但也可以是其它的值 如果表达式是promise对象, await返回的是promise成功的值 如果表达式是其它值, 直接将此值作为await的返回值
注意: await必须写在async函数中, 但async函数中可以没有await 如果await的promise失败了, 就会抛出异常, 需要通过try...catch来捕获处理 为什么用async和await 简化promise对象的使用, 不用再通过then指定回调函数取结果数据 回调地狱的终极解决方案
- 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
// async函数的返回值为promise对象
async function fn1() {
// return 1
// throw 2
// return Promise.reject(3)
return Promise.resolve(4)
}
const result = fn1()
console.log(result)
function fn3() {
// return 3
// return Promise.resolve(5)
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(6)
}, 2000);
})
}
// async函数会立即执行结束返回一个pending状态的promise对象
async function fn2() {
// await后面的代码会放入then()的成功回调中执行的
const result = await fn3()
console.log(result)
}
// fn2()
// console.log('fn2()之后')
// 与async + await的效果是一样的
function fn4() {
return fn3().then(result => {
console.log(result)
})
}
// fn4()
// console.log('fn4()之后')
async function fn5() {
throw 6
}
async function fn6() {
try { // 使用try...catch来处理await后的promise的失败
const result = await fn5()
console.log('fn6 result=', result)
} catch (error) {
console.log('error', error)
}
}
fn6()
看看输出什么?
- 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
async function async1() {
console.log('async1 start')
await async2() // async2().then(() => {})
console.log('async1 end')
}
async function async2() {
console.log('async2')
}
console.log('script start')
setTimeout(() => {
console.log('setTimeout')
}, 0)
async1()
new Promise(function (resolve) {
console.log('promise1')
resolve()
}).then(function () {
console.log('promise2')
})
console.log('script end')
宏队列与微队列
在准备取出每个宏任务准备执行前要执行完所有的微任务
宏队列与微队列理解
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
setTimeout(() => {
console.log('setTimeout callback()', 1)
Promise.resolve(5).then(value => {
console.log('onResolved3()', value)
})
}, 0)
setTimeout(() => {
console.log('setTimeout callback()', 2)
}, 0)
Promise.resolve(3).then(value => {
console.log('onResolved()', value)
})
Promise.resolve(4).then(value => {
console.log('onResolved2()', value)
})
// 3 5 4 1 2
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
setTimeout(() => {
console.log(1)
}, 0)
Promise.resolve().then(() => {
console.log(2)
})
Promise.resolve().then(() => {
console.log(4)
})
console.log(3)
// 3 2 4 1
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
setTimeout(() => {
console.log(1)
}, 0)
new Promise((resolve) => {
console.log(2)
resolve()
}).then(() => {
console.log(3)
}).then(() => {
console.log(4)
})
console.log(5)
// 2 5 3 4 1
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
const first = () => (new Promise((resolve, reject) => {
console.log(3)
let p = new Promise((resolve, reject) => {
console.log(7)
setTimeout(() => {
console.log(5)
resolve(6)
}, 0)
resolve(1)
})
resolve(2)
p.then((arg) => {
console.log(arg)
})
}))
first().then((arg) => {
console.log(arg)
})
console.log(4)
//3 7 4 1 2 5
- 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
setTimeout(() => {
console.log("0")
}, 0)
new Promise((resolve, reject) => {
console.log("1")
resolve()
}).then(() => {
console.log("2")
new Promise((resolve, reject) => {
console.log("3")
resolve()
}).then(() => {
console.log("4")
}).then(() => {
console.log("5")
})
}).then(() => {
console.log("6")
})
new Promise((resolve, reject) => {
console.log("7")
resolve()
}).then(() => {
console.log("8")
})
//1 7 2 3 8 4 6 5 0