(一)promise构造函数
<script type="text/javascript">
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('foo')
},300)
})
myPromise
.then((value) => {
console.log(value,'value')
})
.catch((err) => {
console.log(err)
})
console.log(myPromise,'myPromise')
</script>
(二)将基于回调的 API 转换为基于 Promise 的 API
function myAsyncFunction(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET',url);
xhr.onload=() => resolve(xhr.responseText);
xhr.onerror=() => reject(xhr.statusText);
xhr.send();
})
}
(三)Promise.all()
Promise.all()
静态方法接受一个 Promise 可迭代对象作为输入,并返回一个 Promise。当所有输入的 Promise 都被兑现时,返回的 Promise 也将被兑现(即使传入的是一个空的可迭代对象),并返回一个包含所有兑现值的数组。如果输入的任何 Promise 被拒绝,则返回的 Promise 将被拒绝,并带有第一个被拒绝的原因。
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo')
});
Promise.all([promise1,promise2,promise3]).then((value) => {
console.log(value)
})
<script type="text/javascript">
// 所有的值都不是Promise,因此返回的Promise将被兑现
const p = Promise.all([1,2,3]);
// 输入中唯一的Promise已经被兑现,因此返回的Promise将被兑现
const p2 = Promise.all([1,2,3,Promise.resolve(444)]);
// 一个也是唯一的一个 输入Promise被拒绝,因此返回的Promise将被拒绝
const p3 = Promise.all([1,2,3,Promise.reject(555)]);
// 使用setTimeout,我们因此可以在队列为空后执行代码
setTimeout(() => {
console.log(p);
console.log(p2);
console.log(p3);
})
</script>
状态为fulfilled 和rejected
(四)Promise.all 的异步性和同步性
如果 Promise.all
失败,也是一样的:
只有当传递给
Promise.all
的 iterable
为空时,Promise.all
才会同步解
const p = Promise.all([]);// 将会立即解决
const p2 = Promise.all([1377, 'hi']);// 非promise值将被忽略,但求值是异步进行的
console.log(p);
console.log(p2);
setTimeout(() => {
console.log("队列现在为空");
console.log(p2)
})
(五)将 Promise.all() 与异步函数一起使用
function promptForDishChoice() {
return new Promise((resolve,reject) => {
const dialog = document.createElement("dialog");
dialog.innerHTML = `
<form method="dialog">
<p> What would you like to eat?</p>
<select>
<option value="pizza">Pizza</option>
<option value="pasta">Pasta</option>
<option value="salad">Salad</option>
</select>
<menu>
<li><button value="cancel">Cancel</button></li>
<li><button type="submit" value="ok">OK</button></li>
</menu>
</form>
`;
dialog.addEventListener("close",() => {
if(dialog.returnValue === "ok") {
resolve(dialog.querySelector("select").value)
} else {
reject(new Error("user canceled dialog"))
}
});
document.body.appendChild(dialog);
dialog.showModal();
})
}
async function fetchPrices() {
const response = await promptForDishChoice();
console.log(response,'response')
// return await response.json();
}
fetchPrices()
promise.all()
async function getPrice () {
const [choice, prices] = await Promise.all([
promptForDishChoice(),
fetchPrice(),
]);
return prices[choice]
}
Promise.all 的快速失败行为
Promise.all
在任意一个传入的 promise 失败时返回失败。例如,如果你传入四个超时后解决的 promise 和一个立即拒绝的 promise,那么 Promise.all
将立即被拒绝。
const p1 = new Promise((resolve, reject) => {
setTimeout(() => resolve("一"),1000);
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => resolve("二"),2000);
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => resolve("三"),3000);
})
const p4 = new Promise((resolve, reject) => {
setTimeout(() => resolve("四"),4000);
})
const p5 = new Promise((resolve, reject) => {
reject(new Error("拒绝"))
})
// 使用.catch
Promise.all([p1,p2,p3,p4,p5])
.then((values) => {
console.log(values)
})
.catch((error) => {
console.log(error.message)
})
通过处理可能的拒绝,可以更改此行为:
(六) Promise.allSettled()
Promise.allSettled()
静态方法将一个 Promise 可迭代对象作为输入,并返回一个单独的 Promise,当所有输入的 Promise都已敲定时(包括传入空的可迭代对象时),返回的 Promise 将被兑现,并带有描述每个 Promise结果的对象数组。
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => {
setTimeout(reject, 100, 'foo')
})
const promises = [promise1, promise2];
Promise.allSettled(promises).then((results) => {
results.forEach((result) => {
console.log(result.status)
})
})
(七)Promise.any()
Promise.any()
静态方法将一个 Promise 可迭代对象作为输入,并返回一个 Promise。当输入的任何一个 Promise 兑现时,这个返回的 Promise 将会兑现,并返回第一个兑现的值。当所有输入 Promise 都被拒绝(包括传递了空的可迭代对象)时,它会以一个包含拒绝原因数组的 AggregateError 拒绝。
Promise.any()
会以第一个兑现的 Promise 来兑现,即使有 Promise 先被拒绝。这与 Promise.race() 不同,后者会使用第一个敲定的 Promise 来兑现或拒绝。
如果没有 Promise 被兑现,Promise.any()
将使用 AggregateError 进行拒绝。
在这个例子,我们有一个获取图片并返回 blob 的函数,我们使用 Promise.any()
来获取一些图片并显示第一张可用的图片(即最先解决的那个 promise)。
async function fetchAndDecode(url, description) {
const res = await fetch(url);
if(!res.ok) {
throw new Error(`HTTP错误!状态码:${res.status}`)
}
const data = await res.blob();
return [data, description]
}
const coffee = fetchAndDecode("coffee.jpg","Coffee");
const tea = fetchAndDecode('tea.jpg','Tea');
Promise.any([coffee, tea])
.then(([blob, description]) => {
const objectURL = URL.createObjectURL(blob);
const image = document.createElement("img");
image.src = objectURL;
image.alt = description;
document.body.appendChild(image)
})
.catch((e) => {
console.error(e)
})
(八)Promise.prototype.catch()
Promise 实例的 catch()
方法用于注册一个在 promise 被拒绝时调用的函数。它会立即返回一个等效的 Promise 对象,这可以允许你链式调用其他 promise 的方法。此方法是 Promise.prototype.then(undefined, onRejected) 的一种简写形式。
在异步函数内部抛出的错误会像未捕获的错误一样:
(九)Promise.prototype.finally()
Promise 实例的 finally()
方法用于注册一个在 promise 敲定(兑现或拒绝)时调用的函数。它会立即返回一个等效的 Promise 对象,这可以允许你链式调用其他 promise 方法。
这可以让你避免在 promise 的 then() 和 catch() 处理器中重复编写代码。
let isLoading = true;
fetch(myRequest)
.then((response) => {
const contentType = response.headers.get("content-type");
if(contentType && contentType.includes("application/json")) {
return response.json()
}
throw new TypeError('ERROR ERROR')
}).then((json) => {
}).catch((error) => {
console.error(error)
}).finally(() => {
isLoading = false
})
(十)Promise.race()
Promise.race()
静态方法接受一个 promise 可迭代对象作为输入,并返回一个 Promise。这个返回的 promise 会随着第一个 promise 的敲定而敲定。
<script type="text/javascript">
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'ONE')
})
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'TWO')
})
Promise.race([promise1, promise2]).then((value) => {
console.log(value)
})
</script>
使用 Promise.race()
这个例子展示了如何使用 Promise.race()
来比较多个使用 setTimeout() 实现的计时器。计时时间最短的计时器总是赢得竞态,并成为返回的 promise 状态。
<script type="text/javascript">
function sleep(time,value,state) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if(state === "兑现") {
return resolve(value)
} else {
return reject(new Error(value))
}
},time)
})
}
const p1 = sleep(500, '一', "兑现");
const p2 = sleep(100, '二', "兑现");
Promise.race([p1,p2]).then((value) => {
console.log(value)
})
const p3 = sleep(500, '三', "兑现");
const p4 = sleep(100, '四', "拒绝");
Promise.race([p3,p4]).then(
(value) => {
console.log(value)
},
(error) => {
console.log(error.message)
}
)
const p5 = sleep(500, '五', "兑现");
const p6 = sleep(100, '六', "拒绝");
Promise.race([p5,p6]).then(
(value) => {
},(error) => {
console.log(error.message)
}
)
</script>
Promise.race 的异步性
以下示例演示了 Promise.race
的异步性。与其他 promise 并发方法不同,Promise.race
总是异步的:即使 iterable
为空,它也永远不会同步地完成。
// 传入一个已经解决的Promise数组,以尽快触发Promise.race
const resolvedPromiseArray = [Promise.resolve(33), Promise.resolve(44)];
const p = Promise.race(resolvedPromiseArray);
// 立即打印p的值
console.log(p);
// 使用setTimeout.我们可以在堆栈为空后执行代码
setTimeout(() => {
console.log("堆栈现在为空");
console.log(p)
})
一个空的可迭代对象会导致返回的 Promise 一直处于待定状态:
const foreverPendingPromise = Promise.race([]);
console.log(foreverPendingPromise);
setTimeout(() => {
console.log("堆栈现在为空");
console.log(foreverPendingPromise)
})
如果可迭代对象包含一个或多个非 Promise 值和/或一个已经敲定的 Promise,则 Promise.race
会以数组中找到的第一个这样的值敲定:
const foreverPendingPromise = Promise.race([]);
const alreadyFulfilledProm = Promise.resolve(100);
const arr = [foreverPendingPromise,alreadyFulfilledProm,"非Promise值"];
const arr2 = [foreverPendingPromise,'非Promise值',Promise.resolve(100)]
const p = Promise.race(arr);
const p2 = Promise.race(arr2);
console.log(p);
console.log(p2);
setTimeout(() => {
console.log("堆栈现在为空");
console.log(p);
console.log(p2);
})
使用 Promise.race() 实现请求超时
你可以使用一个定时器来与一个可能持续很长时间的请求进行竞争,以便超出时间限制时,返回的 Promise 自动拒绝。
const data = Promise.race([
fetch('/api'),
new Promise((resolve, reject) => {
// 5秒后拒绝
setTimeout(() => reject(new Error('请求超时')),5000)
})
])
.then((res) => res.json())
.catch((err) => displayError(err))
使用 Promise.race() 检测 Promise 的状态
const p1 = new Promise((res) => setTimeout(() => res(100), 100));
const p2 = new Promise((res) => setTimeout(() => res(200), 200));
const p3 = new Promise((res, rej) => setTimeout(() => rej(300), 100));
function promiseState(promise) {
const pendingState = { status: "待定" };
return Promise.race([promise, pendingState]).then(
(value) => (value === pendingState ? value : { status: "已兑现", value }),
(reason) => ({ status: "已拒绝", reason }),
);
}
async function getStates() {
console.log(await promiseState(p1));
console.log(await promiseState(p2));
console.log(await promiseState(p3));
}
console.log("开始状态:");
getStates();
setTimeout(() => {
console.log("等待 100ms 后:");
getStates();
}, 100);
与 Promise.any() 的比较
Promise.race
方法以可迭代对象中第一个敲定的 Promise 作为敲定值。
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, "一");
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(reject, 100, "二");
});
Promise.race([promise1, promise2])
.then((value) => {
console.log("成功,值为:", value);
})
.catch((reason) => {
// 只有 promise1 成功兑现,但 promise2 更快
console.error("失败,原因为:", reason);
});
// 失败,原因为:二
Promise.any 方法以可迭代对象中第一个被兑现的 Promise 作为兑现值。
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, "一");
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(reject, 100, "二");
});
Promise.any([promise1, promise2])
.then((value) => {
// 只有 promise1 成功兑现,即使 promise2 更快敲定
console.log("成功,值为:", value);
})
.catch((reason) => {
console.error("失败,原因为:", reason);
});
// 成功,值为:一
Promise.reject()
Promise.reject()
静态方法返回一个已拒绝(rejected)的 Promise
对象,拒绝原因为给定的参数。
function resolved(result) {
console.log('Resolved')
}
function rejected(result) {
console.error(result)
}
Promise.reject(new Error('fail'))
.then(resolved,rejected)
Promise.reject
静态方法返回一个被拒绝的 Promise
对象。
该函数可以用 resolve
和 reject
回调函数作为参数进行调用。Promise.reject()
实际上相当于 new Promise((resolve, reject) => reject(reason))
的简写形式。
使用 Promise.reject() 静态方法
Promise.reject(new Error("失败"))
.then(
() => {
// 不会被调用
},
(error) => {
console.error(error)
}
)
reject 一个 promise 对象
与 Promise.resolve 不同,Promise.reject
方法不会重用已存在的 Promise
实例。它始终返回一个新的 Promise
实例,该实例封装了拒绝的原因(reason
)。
在非 Promise 构造函数上调用 reject()
Promise.resolve()
使用 Promise.resolve 静态方法
resolve 另一个 promise
Promise.resolve()
方法会重用已存在的 Promise
实例。如果它正在解决一个原生的 Promise,它将返回同一 Promise 实例,而不会创建一个封装对象。
resolve thenable 对象并抛出错误
<script type="text/javascript">
// Resolve一个thenable对象
const p1 = Promise.resolve({
then(onFulfill,onReject) {
onFulfill("已兑现")
}
})
console.log(p1 instanceof Promise);
p1.then(
(v) => {
console.log(v)
},
(e) => {
// 不会被调用
}
)
// Thenable 在回调之前抛出异常
// Promise被拒绝
const thenable = {
then(onFulfilled) {
throw new TypeError("抛出异常");
onFulfilled("Resolving")
}
}
const p2 = Promise.resolve(thenable);
p2.then(
(v) => {
// 不会被调用
},
(e) => {
console.error(e)// 抛出异常
}
)
// Thenable在回调Promise被解决之后抛出异常
const thenable1 = {
then(onFulfilled) {
onFulfilled("解决");
throw new TypeError("Throwing")
}
}
const p3 = Promise.resolve(thenable1);
p3.then(
(v) => {
console.log(v);// 解决
},
(e) => {
// 不会被调用
}
)
</script>
嵌套的 thenable 对象将被“深度展平”为单个 Promise 对象
const thenable = {
then(onFulfilled,onRejected) {
onFulfilled({
// 该thenable对象将兑现为另外一个thenable对象
then(onFulfilled,onRejected) {
onFulfilled(42)
}
})
}
}
Promise.resolve(thenable).then((v) => {
console.log(v);// 12
})
警告: 不要在一个解决为自身的 thenable 对象上调用 Promise.resolve()
。这将导致无限递归,因为它试图展平一个无限嵌套的 Promise。
const thenable = {
then(onFulfilled, onRejected) {
onFulfilled(thenable);
},
};
Promise.resolve(thenable); // 将会导致无限递归。
在非 Promise 构造函数上调用 resolve()
class NotPromise {
constructor(executor) {
executor(
(value) => console.log("已解决",value),
(reason) => console.log("已拒绝",reason)
)
}
}
Promise.resolve.call(NotPromise, 'foo');// 输出 “已解决foo”
const thenable = {
then(onFulfilled, onRejected) {
onFulfilled({
// 该 thenable 对象将兑现为另一个 thenable 对象
then(onFulfilled, onRejected) {
onFulfilled(42);
},
});
},
};
Promise.resolve.call(NotPromise, thenable); // 输出 "已兑现 { then: [Function: then] }"
Promise.prototype.then()
参数
onFulfilled
可选
一个在此 Promise 对象被兑现时异步执行的函数。它的返回值将成为 then()
返回的 Promise 对象的兑现值。此函数被调用时将传入以下参数:
onRejected
可选
一个在此 Promise 对象被拒绝时异步执行的函数。它的返回值将成为 catch()
返回的 Promise 对象的兑现值。此函数被调用时将传入以下参数:
<script type="text/javascript">
Promise.resolve("foo")
// 1.接收foo并与bar 拼接,并将其结果作为下一个resolve返回
.then(
(string) => {
new Promise((resolve, reject) => {
setTimeout(() => {
string += "bar";
resolve(string)
},1)
})
}
)
// 2.接收“foobar",放入一个异步函数中处理该字符串
// 并将其打印到控制台中,但是不将处理后的字符串返回到下一个
.then((string) => {
setTimeout(() => {
string += "baz";
console.log(string);// foobarbaz
},1);
return string;
})
// 3.打印本节中代码将如何运行的帮助消息
// 字符串实际上是由
.then((string) => {
console.log(
"最后一个 then:哎呀……之前懒得实例化并返回一个 Promise,所以顺序可能有点令人惊讶"
);
// 注意string这时不会存在baz
// 因为这是发生在我们通过settimeout模拟的异步函数中
console.log(string)// foobar
})
// 按照顺序打印:
// 最后一个then:
// foobar
// foobarbaz
</script>
如果 onFulfilled
返回一个 Promise,那么 then
的返回值将根据该 Promise 的最终状态被兑现或被拒绝。
<script type="text/javascript">
function resolveLater(resolve,reject) {
setTimeout(() => {
resolve(10)
},1000)
}
function rejectLater(resolve,reject) {
setTimeout(() => {
reject(new Error("错误"))
},1000)
}
const p1 = Promise.resolve("foo");
const p2 = p1.then(() => {
// 此处返回一个Promise,将在1秒后解决为10
return new Promise(resolveLater)
})
p2.then(
(v) => {
console.log("已解决",v);// 已解决 10
},
(e) => {
// 不会被调用
console.error("已拒绝",e)
}
)
const p3 = p1.then(() => {
// 此处返回一个promise,将在1秒后以"错误"被拒绝
return new Promise(rejectLater)
})
p3.then(
(v) => {
// 不会被调用
console.log("已解决",v)
},
(e) => {
console.error("已拒绝",e)// “已拒绝”,"错误"
}
)
</script>
你可以使用链式调用,在一个函数上实现基于 Promise 的 API,在另一个函数之上。
参考原文:(以上都是来自官方文档,此文档仅供学习参考笔记记录)