JavaScript 基础
Document
运算符
深入数据和类型
函数进阶
原型、继承
类
浏览器存储
Web API
事件
错误处理
异步编程
网络请求
模块
练习
实例
工具与规范
软件架构模式
设计模式
在回调的章节中,我们使用回调函数来接收执行的结果。很多时候,我们的需求都是固定的,我们需要获知执行状态,执行结果要不成功要不失败。因此 JavaScript 提供了 Promise 对象封装了这些相关的属性和方法。
语法如下:
let promise = new Promise(function(resolve, reject) {
// resolve 执行成功调用
// reject 执行失败调用
});
Promise 接收一个函数,函数有两个参数 resolve、reject:
- resolve:应在任务执行成功时调用。
- reject:应在任务执行失败时调用。
我们改写一下上节课回调的例子:
$$jsdemo$$
$$edit$$
function loadFile() {
// 读取文件需要三秒钟
return new Promise(function (resolve) {
setTimeout(function () {
const file = "三眼鸭的编程教室"
// 将结果作为参数传到 resolve 中
resolve(file)
}, 3000)
})
}
console.log("开始执行") // 同步执行
const promise = loadFile()
promise.then(function (file) {
// 得到执行结果
console.log(`文件内容:${file}`) // 文件内容:三眼鸭的编程教室
})
console.log("结束执行") // 同步执行
我们把回调函数作为 then
的第一个参数。而此时,通过执行 resolve
可以调用我们传进去的回调函数。
then、catch、finally
Promise 有三个方法,then、 catch、 finally,可供我们传递回调函数来处理执行结果。
then
then 可以接收两个函数作为参数,分别处理 resolve
和 reject
的结果,语法如下:
promise.then(
function (result) {
/* 处理执行成功的结果 */
},
function (error) {
/* 处理执行失败的结果 */
}
)
$$jsdemo$$
$$edit$$
function loadFile() {
// 读取文件需要三秒钟
return new Promise(function (resolve, reject) {
setTimeout(function () {
// 假设有一半的概率读取失败
if (Math.random() < 0.5) {
const file = "三眼鸭的编程教室"
// 将结果作为参数传到 resolve 中
resolve(file)
} else {
// 失败
reject("网络中断")
}
}, 3000)
})
}
console.log("开始执行") // 同步执行
const promise = loadFile()
promise.then(
function (file) {
// 得到执行结果
console.log(`文件内容:${file}`) // 文件内容:三眼鸭的编程教室
},
function (error) {
// 失败处理
console.log(`失败,原因是:${error}`)
}
)
console.log("结束执行") // 同步执行
catch
catch 接收一个函数作为参数,用以处理执行失败的结果,语法如下:
promise.catch(function (error) {
/* 处理执行失败的结果 */
})
当然,这跟我们设置 then
的第一个参数为 null,只设置第二个参数等价的:
promise.then(
null,
function (error) {
/* 处理执行失败的结果 */
})
finally
不管执行成功还是执行失败都会被执行。
promise.finally(
function () {
/* 总是会执行 */
})
Promise 链
promise 的回调中 return 的值会作为下一个 then 中的参数,这便被称为 Promise 链。
$$jsdemo$$
$$edit$$
let promise = new Promise(function (resolve, reject) {
resolve("三眼鸭")
})
promise
.then(function (value) {
console.log(value) // 三眼鸭
return "三眼鸡"
})
.then(function (value) {
console.log(value) // 三眼鸡
return "三眼鹅"
})
.then(function (value) {
console.log(value) // 三眼鹅
})
如果返回的是一个 promise, 那么会等待其结果后。
$$jsdemo$$
$$edit$$
let promise = new Promise(function (resolve, reject) {
resolve("三眼鸭")
})
promise
.then(function (value) {
console.log(value) // 三眼鸭
return new Promise(function (resolve, reject) {
setTimeout(() => resolve("三眼鸡"), 3000)
})
})
.then(function (value) {
console.log(value) // 三眼鸡
})
如果抛出了一个错误,那么便会被接下来的 catch 捕获到。
$$jsdemo$$
$$edit$$
let promise = new Promise(function (resolve, reject) {
resolve("三眼鸭")
})
promise
.then(function (value) {
throw "错误"
})
.catch(function (error) {
console.log(error) // 错误
})
Promise.all
Promise.all
接收 promise
的可迭代对象(Array、Set 等),并返回一个新的 promise
。Promise.all
的 promise
在可迭代对象的所有 promise
执行完成后执行,并且 resolve
的参数为所有可迭代对象的 promise
结果。
$$jsdemo$$
$$edit$$
function after1s() {
return new Promise(function (resolve) {
setTimeout(function () {
resolve("1s")
}, 1000)
})
}
function after3s() {
return new Promise(function (resolve) {
setTimeout(function () {
resolve("3s")
}, 3000)
})
}
Promise.all([after1s(), after3s()]).then(function (result) {
console.log(result) // ['1s', '3s']
})
如果可迭代对象中任意一个 promise
执行 reject
则立刻执行Promise.all
的 promise
的 reject
。
$$jsdemo$$
$$edit$$
function after1s() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
reject(new Error("执行出错"))
}, 1000)
})
}
function after3s() {
return new Promise(function (resolve) {
setTimeout(function () {
resolve("3s")
}, 3000)
})
}
Promise.all([after1s(), after3s()])
.then(function (result) {
console.log(result)
})
.catch(function (error) {
console.log(error.message) // 执行出错
})
练习
- 使用
promise
改写以下的回调函数。
$$jsdemo$$
$$edit$$
function doAfter3s(callback) {
setTimeout(function () {
callback("三眼鸭的编程教室")
}, 3000)
}
doAfter3s((word) => alert(word))
$$answer
$$jsdemo$$
$$edit$$
function doAfter3s() {
return new Promise(function (resolve) {
setTimeout(function () {
resolve("三眼鸭的编程教室")
}, 3000)
})
}
doAfter3s().then((word) => alert(word))
$$
- 有以下几个
promise
函数,求出所有resolve
结果的和。
function x() {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(10)
}, 3000)
})
}
function y() {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(5)
}, 1000)
})
}
function z() {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(20)
}, 2000)
})
}
$$answer
$$jsdemo$$
$$edit$$
function x() {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(10)
}, 3000)
})
}
function y() {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(5)
}, 1000)
})
}
function z() {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(20)
}, 2000)
})
}
Promise.all([x(), y(), z()]).then(function (result) {
alert(result.reduce((a, b) => a + b))
})
$$