当前位置:网站首页>js 期约与异步函数 Promise
js 期约与异步函数 Promise
2022-06-28 12:07:00 【飞天巨兽】
《JavaScript高级程序设计》读书笔记
期约
创建期约需要传入执行器函数作为参数
let p = new Promise(()=>{})
console.log(p); // Promise {<pending>}1. 期约状态
- 待定(pending)
- 兑现(fulfilled,有时候也称为“解决”,resolved)
- 拒绝(rejected)
2. 通过执行函数控制期约状态
期约状态是私有的,所以只能在内部进行操作。通过调用它的两个函数参数实现,通常命名为reslove() 和 reject() 。状态落定后是不可逆的。
3. Promise.resolve()
可以实例化一个解决的期约。接收一个参数,可以把任何值都转化为一个期约,包括错误对象。如果本身是一个期约,它的行为类似一个空包装。因此,可以说是一个幂等方法。
let p1 = new Promise((resolve, reject) => resolve());
// 等价于
let p2 = Promise.resolve(); // Promise {<fulfilled>: undefined}
let p3 = Promise.resolve(3); // Promise {<fulfilled>: 3}
p3 === Promise.resolve(p3); // true
Promise.resolve(new Error('foo')); // Promise {<fulfilled>: Error: foo4. Promise.reject()
如果传入一个期约对象,则这个期约会成为它返回拒绝期约的理由。
let p1 = new Promise((resolve, reject) => reject());
// 等价于
let p2 = Promise.reject(); // Promise {<rejected>: undefined}
Promise.reject(3); // Promise {<rejected>: 3}
Promise.reject(Promise.resolve()); // Promise {<rejected>: Promise}期约的实例方法
1. Promise.prototype.then()
接收两个可选参数:onResolved 处理程序和 onRejected 处理程序。对于非函数处理程序会被静默忽略。如果没有显示的返回语句,则原样往后传,默认的返回值 undefined。抛出异常会返回拒绝的期约。
let p =Promise.resolve('foo');
p.then(() => console.log('res'), () => console.log('rej')); // res
p.then(() => {throw 'bar'}, () => console.log('rej')); // Promise {<rejected>: 'bar'}2. Promise.prototype.catch()
一个语法糖,用于给期约添加错误处理程序。只接收一个参数:onRejected 处理程序。相当于调用 Promise.prototype.then(null, onRejected);
3. Promise.prototype.finally()
用于给期约添加 onFinally 处理程序,这个程序在期约转换为解决或拒绝状态时都会执行。
4. 非重入期约方法
当期约进入落地状态时,与该状态相关的处理程序仅仅会被排期,而非立即执行。跟着这个程序后面的同步代码一定会在该程序之前先执行。即使期约一开始就是与附加处理程序关联的状态。
5. 邻近处理程序的执行顺序
如果给期约添加了多个处理程序,当期约状态变化时,相关处理程序会被按照添加它们的顺序依次执行。
let p1 = Promise.resolve();
p1.then(() => setTimeout(console.log, 0, 1));
p1.then(() => setTimeout(console.log, 0, 2));
// 1
// 2静态方法
promise.all()
会在一组期约全部解决之后再解决。接收一个可迭代对象,返回一个新的期约。
返回值:
- 如果传入的参数是一个空的可迭代对象,则返回一个已完成(already resolved)状态的Promise Promise。
- 如果传入的参数不包含任何
promise,则返回一个异步完成(asynchronously resolved) 的Promise。 - 其它情况下返回一个处理中(pending)的Promise。这个返回的
promise之后会在所有的promise都完成或有一个promise失败时异步地变为完成或失败。
promise.race()
是一组集合中最先解决或拒绝的期约的镜像。接收一个可迭代对象,返回一个新的期约。只要是第一个落地的期约,就会包装其解决值或拒绝理由并返回新的期约。
串行期约合成
基于后续期约使用之前期约的返回值来串联期约。
function compose(...fns) {
return (x) => fns.reduce((promise, fn) => promise.then(fn), Promise.resolve(x));
}期约扩展
1. 期约取消
<body>
<button id="start">Start</button>
<button id="cancel">Cancel</button>
</body>
<script>
class CancelToken {
constructor(cancelFn){
this.promise = new Promise((resolve, reject) => {
cancelFn(() => {
setTimeout(console.log, 0 ,"delayed cancelled");
resolve();
})
})
}
}
const startButton = document.getElementById('start');
const cancelButton = document.getElementById('cancel');
function cancellableDelayedResolve(delay){
setTimeout(console.log, 0, "set delay");
return new Promise((resolve, reject) => {
const id = setTimeout((() => {
setTimeout(console.log, 0, "delayed resolve")
resolve();
}), delay);
const cancelToken = new CancelToken((cancelCallback) =>
cancelButton.addEventListener("click", cancelCallback)
)
cancelToken.promise.then(() => clearTimeout(id));
});
}
startButton.addEventListener("click", () => cancellableDelayedResolve(1000));
</script>2. 期约进度通知
class TrackablePromise extends Promise {
constructor(executor) {
const notifyHandlers = [];
super((resolve, reject) => {
return executor(resolve, reject, (status) => {
notifyHandlers.map((handler) => handler(status));
});
});
this.notifyHandlers = notifyHandlers;
}
notify(notifyHandler) {
this.notifyHandlers.push(notifyHandler);
return this;
}
}
let p = new TrackablePromise((resolve, reject, notify) => {
function countdown(x) {
if(x > 0){
notify(`${20 * x }% remaining`);
setTimeout(() => countdown(x -1), 1000);
} else {
resolve();
}
}
countdown(5);
});
p.notify((x) => setTimeout(console.log, 0, 'progress:', x));
p.then(() => setTimeout(console.log, 0, 'completed'));
// (约1秒后) progress: 80% remaining
// (约2秒后) progress: 60% remaining
// (约3秒后) progress: 40% remaining
// (约4秒后) progress: 20% remaining
// (约5秒后) completed异步函数
1. async
用于声明异步函数。可以用在函数声明、函数表达式、箭头函数和方法上。异步函数如果使用了return 关键字返回值(如果没有return 则返回undefined),该值会被 Promise.resolve() 包装成一个期约对象。
异步函数的返回值期待一个实现 thenable 接口的对象,常规的值也可以。如果返回的是实现 thenable 接口的对象,则可以由then() “解包”。如果不是,则返回值就被当作已经解决的期约。
async function foo() {
return 'foo'
}
foo().then(console.log); // foo
async function bar() {
return ['bar']
}
bar().then(console.log); // ['bar']
async function baz() {
const thenable = {
then(callback) { callback('baz'); }
};
return thenable;
}
baz().then(console.log); // baz
2. await
暂停异步函数代码的执行,等待期约解决。async/await 中真正起作用的是 await。异步函数如果不包含await 关键字,其执行基本上跟普通函数一样。
async function foo() {
console.log(await 'foo');
}
foo(); // foo3. await 的限制
必须在异步函数中使用,不能再顶级上下文如<script> 标签或模块中使用。
异步函数策略
1. 实现sleep()
async function sleep(delay) {
return new Promise((resolve) => setTimeout(resolve, delay));
}
async function foo() {
const t0 = Date.now();
await sleep(1500);
console.log(Date.now() - t0);
}
foo(); // 15142. 利用平行执行
async function randomDelay(id) {
const delay = Math.random() * 1000;
return new Promise((resolve) => setTimeout(() => {
console.log(`${id} finished`);
resolve(id);
}, delay));
}
async function foo() {
const t0 = Date.now();
const promises = Array(5).fill(null).map((_, i) => randomDelay(i));
for(const p of promises) {
console.log(`awaited ${await p}`);
}
console.log(`${Date.now() - t0} ms elapsed`);
}
foo();
// 2 finished
// 1 finished
// 4 finished
// 3 finished
// 0 finished
// awaited 0
// awaited 1
// awaited 2
// awaited 3
// awaited 4
// 945 ms elapsed3. 串行执行期约
async function addTwo(x) {
return x + 2;
}
async function addThree(x) {
return x + 3;
}
async function addFive(x) {
return x + 5;
}
async function addTen(x) {
for( const fn of [addTwo, addThree, addFive]) {
x = await fn(x);
}
return x;
}
addTen(9).then(console.log); // 19边栏推荐
- What is data compliance? How to achieve data compliance?
- AcWing 606. Average 1 (implemented in C language)
- 【Unity编辑器扩展基础】、GUILayout
- [vi/vim] basic usage and command summary
- Research on personalized product search
- Allez, Meta - Cosme, comme prévu, cette chaleur ne durera pas longtemps.
- 【Unity编辑器扩展实践】、查找所有引用该图片的预制体
- AcWing 605. Simple product (implemented in C language)
- MapReduce项目案例3——温度统计
- 30套JSP网站源代码合集「建议收藏」
猜你喜欢

Web3安全连载(3) | 深入揭秘NFT钓鱼流程及防范技巧

KDD 2022 | 图“预训练、提示、微调”范式下的图神经网络泛化框架

EMC RS485接口EMC电路设计方案

UGUI使用小技巧(六)Unity实现字符串竖行显示

【Unity编辑器扩展实践】、利用txt模板动态生成UI代码

In less than an hour, apple destroyed 15 startups

Graphics view framework for QT learning (to realize startup animation)
Using MySQL database in the express framework of node

自定义标题栏View

Django -- MySQL database reflects the mapping data model to models
随机推荐
Bisection (integer bisection and floating point bisection)
Sha256 encryption tool class
Build your own website (18)
RemoteViews布局和类型限制源码分析
运维思考 | 你知道CMDB与监控是什么关系吗?
Web3安全连载(3) | 深入揭秘NFT钓鱼流程及防范技巧
真正的学懂三极管入门篇(经典)「建议收藏」
AcWing 608. Poor (implemented in C language)
MapReduce project case 1
Map sorting tool class
女子高考落榜读专科逆袭买千万别墅,考得不好真的没关系
fatal: unsafe repository (‘/home/anji/gopath/src/gateway‘ is owned by someone else)
【Unity编辑器扩展基础】、EditorGUILayout (三)
Come on, yuanuniverse. Sure enough, the heat won't pass for a while
6.A-B
Redis hash hash type string (5)
PrecomputedTextCompat用法及原理
【经验分享】Django开发中常用到的数据库操作总结
Int~long long indicates the maximum and minimum number
CDC synchronization if the primary key of a database table changes, will it be synchronized into two data or will it be synchronized to update the primary key?