Promise
Promise
第一章 简介
Promise最初被提出是在E语言中,它是基于并列或者并行处理设计的一种编程语言。Promise 是JavaScript中处理异步操作的一种方式,它代表了一个可能尚未完成操作的最终完成或者失败的结果值。Promise 对象的主要目的是提供一种更加灵活的可管理方式来处理异步代码,避免回调地狱(callback hell),使得代码更加清晰和易于维护。
第二章 创建
一个 Promise 是通过 new Promise() 构造器来创建的,构造器接收一个函数(称为执行器函数),该函数有两个参数:resolve 和 reject。
resolve(value):表示操作成功,value是成功时的结果。reject(error):表示操作失败,error是失败时的错误信息。
let promise = new Promise((resolve, reject) => {
let success = true; // 模拟一个异步操作
if (success) {
resolve('操作成功');
} else {
reject('操作失败');
}
});
promise.then(result => {
console.log(result); // 操作成功
}).catch(error => {
console.log(error); // 操作失败
});
第三章 常用方法
then()
then(onFulfilled, onRejected) 是 Promise 的核心方法,用来定义操作成功时的回调函数(onFulfilled)和操作失败时的回调函数(onRejected)。
onFulfilled:异步操作成功时的回调函数,接收resolve传递的值。onRejected:异步操作失败时的回调函数,接收reject传递的错误信息。
返回值: then() 返回一个新的 Promise,使得 then() 具有链式调用的能力。
let promise = new Promise((resolve, reject) => {
resolve('操作成功');
});
promise.then((result) => {
console.log(result); // "操作成功"
}).then(() => {
console.log('继续处理');
});
catch()
catch(onRejected) 用于指定当 Promise 被拒绝(reject)时的回调函数,它等同于 .then(null, onRejected)。
返回值: catch() 返回一个新的 Promise,允许链式调用。
let promise = new Promise((resolve, reject) => {
reject('操作失败');
});
promise.catch((error) => {
console.log(error); // "操作失败"
});
finally()
finally(onFinally) 用于指定无论 Promise 成功还是失败都会执行的回调函数。通常用于清理操作,如关闭文件、释放资源等。
返回值: finally() 返回一个新的 Promise,因此可以继续链式调用。
let promise = new Promise((resolve, reject) => {
resolve('操作成功');
});
promise.then((result) => {
console.log(result); // "操作成功"
}).finally(() => {
console.log('清理操作');
});
小贴士
无论 Promise 是成功还是失败,finally() 中的回调都会被执行。
all()
Promise.all(iterable) 接受一个可迭代对象(通常是一个数组),并返回一个新的 Promise,这个 Promise 会在所有输入的 Promise 都解决(fulfilled)时解决,并返回一个包含所有输入 Promise 结果的数组。
- 如果其中有任何一个
Promise被拒绝(rejected),则Promise.all()返回的Promise会立即被拒绝,并且拒绝的错误为第一个拒绝的Promise的错误。
let promise1 = new Promise((resolve, reject) => setTimeout(resolve, 1000, '结果1'));
let promise2 = new Promise((resolve, reject) => setTimeout(resolve, 2000, '结果2'));
let promise3 = new Promise((resolve, reject) => setTimeout(resolve, 1500, '结果3'));
Promise.all([promise1, promise2, promise3]).then((results) => {
console.log(results); // ["结果1", "结果2", "结果3"]
}).catch((error) => {
console.log(error);
});
第四章 静态方法
Promise.resolve()
Promise.resolve(value)可以认为是new Promise()方法的快捷方式。
// 比如Promise.resolve(42)可以认为是以下代码的语法糖
new Promise(function(resolve){
resolve(42);
});
/*
在这段代码中的resolve(42);
会让这个promise对象立即进入确定(即resolved)状态
并将42传递给后面then里所指定的onFulfilled函数中
其返回值也是一个promise对象
所以我们可以继续对其使用链式调用
*/
Promise.reject()
Promise.reject(error)是和 Promise.resolve(value)类似的静态方法,是new Promise()方法的快捷方式。
// 比如 Promise.reject(new Error("出错了")) 就是下面代码的语法糖形式。
new Promise(function(resolve, reject){
reject(new Error("出错了"));
});
/*
这段代码的功能是调用该promise对象通过then指定的onRejected函数
并将错误(Error)对象传递给这个 onRejected 函数
它和Promise.resolve(value)的不同之处在于promise内调用的函数是reject而不是resolve
这在编写测试代码或者进行debug时,说不定会用得上
*/
第五章 async | await
async和await是基于Promise上的语法糖。可以让异步操作更加简洁明了。
async function test() {
const response = await fetch("https://...");
const json = await response.json();
console.log(json);
}
// 使用async标记函数为异步函数
// 异步函数就是返回值为Promise对象的函数
// 上例中使用await会让后面的代码执行完才会执行下一步
注意
async只能用于函数。await只能运用在async标记的函数内并且只能用于返回值是Promise类型的。
async function test() {
await setTimeout(() => {
console.log("TenSoFlow");
}, 3000)
console.log("Hello World!")
}
test();
// 这样写照样是异步的,会先打印'Hello World!'。因为await只能作用于返回值类型是Promise类型的。
// 下面给出正确的写法,只需将setTimeout包装成一个异步函数即可
async function test() {
await new Promise((resolve) => {
setTimeout(() => {
console.log("TenSoFlow");
resolve(); // 完成时调用 resolve
}, 3000);
});
console.log("Hello World!");
}
test();
注意
async作用于函数时都会显式或者隐式的返回一个Promise对象
// 隐式返回
const person = {
name: 'John Doe',
age: 30
}
/*
异步函数没有显式返回Promise对象
就会隐式返回一个Promise.resolve(undefined)对象
*/
async function setName (name) {
person.name = name;
}
// 因为隐式的返回了Promise对象就可以链式调用then()
setName('TenSoFlow').then((resolve) => {
console.log(resolve); // undefined
}).catch((reject) => {
console.log(reject);
});
// 显示返回
const person = {
name: 'John Doe',
age: 30
}
// 此时异步函数显式的返回了Promise对象
async function setName (name) {
person.name = name;
/**
* 因为async标记的方法必须返回一个Promise对象
* 因此无论返回什么值,如果没加Promise.resolve()都会自动加上Promise.resolve()
* 如return 1 其实是 return Promise.resolve(1)
*/
return Promise.resolve(undefined)
}
setName('TenSoFlow').then((resolve) => {
console.log(resolve); // undefined
}).catch((reject) => {
console.log(reject);
});
注意
用变量去接收Promise对象则变量毫无疑问是一个Promise对象,代码是异步的。但用变量去接收一个await Promise对象则变量是Promise对象resolve的值(或是异常时抛出的reject错误),此时代码是同步的。
const person = {
name: 'John Doe',
age: 30
}
// 使用 await 的情况(解包 Promise)
async function setName (name) {
console.log('1')
const data = await new Promise(resolve => {
setTimeout(() => {
person.name = name
console.log('name:', person.name) // 异步任务完成时打印
resolve(person.name) // Promise 结果
}, 1000)
})
console.log('data:', data) // 已经解包,拿到真正值
console.log('3')
}
// 不使用 await 的情况(直接拿到 Promise 对象)
async function setAge (age) {
console.log('A')
const data = new Promise(resolve => {
setTimeout(() => {
person.age = age
console.log('age:', person.age) // 异步任务完成时打印
resolve(person.age) // Promise 结果
}, 1000)
})
console.log('data:', data) // Promise 仍然是 pending 状态
console.log('C')
}
setName('John')
// 输出顺序:
// 1
// name: John (1s 后)
// data: John
// 3
setAge(25)
// 输出顺序:
// A
// data: Promise { <pending> }
// C
// age: 25 (1s 后)
