第11章 期约与异步函数#
#第十一章,期约与异步函数
#散碎
#.resolve() 是幂等的,.reject() 不是
const origin = Promise.resolve('inner');
const p = Promise.resolve(origin);
console.log(p === origin, p); // true Promise<fulfilled>: 'inner'
const p2 = Promise.reject(origin);
console.log(p2 === origin, p2); // false Promise<rejected>: Promise#外部 try catch 无法捕捉错误
try {
Promise.reject(1);
} catch (error) {
console.log(error); // 捕获不到,会报错
}#多个串联的期约处理,可以理解为树接口,执行顺序可以理解为层序遍历
// A
// / \
// B C
// / \ / \
// D E F G
let A = new Promise((resolve, reject) => {
console.log('A');
resolve();
});
let B = A.then(() => console.log('B'));
B.then(() => console.log('D'));
let C = A.then(() => console.log('C'));
C.then(() => console.log('F'));
B.then(() => console.log('E'));
C.then(() => console.log('G'));
// A B C D E F G#有方法会静默处理错误(.all、.race
后续解决或拒绝的期约将不再影响返回的期约的状态。这种行为称为“静默处理”,意味着后续的拒绝不会触发任何错误或被捕获的拒绝处理程序。(catch 会触发的话,只能被触发一次
let p = Promise.race([Promise.reject(1), new Promise((_, reject) => reject(2))]);
p.catch(reason => setTimeout(console.log, 0, reason)); // 1 (之后不再处理2#串行期约组合合并处理
const add_2 = x => x + 2;
const add_4 = x => x + 4;
const add_8 = x => x + 8;
const fns = [add_2, add_4, add_8];
const compose = fns => {
return x => fns.reduce((p, fn) => p.then(fn), Promise.resolve(x));
};
const flow = compose(fns);
flow(1).then(result => {
console.log(result);
});#期约取消与进度
es6+ 并没有实现取消与进度,委员会认为取消与进度是激进的;如果实现取消与进度,会让期约连锁和合成过度复杂
#期约取消
我不知道为何书上要那样写,感觉总是不直观,以下借鉴进度的写法实现取消
<button id="start">Start</button>
<button id="cancel">Cancel</button>
<script>
const startBtn = document.querySelector('#start')
const cancelBtn = document.querySelector('#cancel')
class CouldCancelPromise {
constructor(executor) {
// 保留原来的 resolve,reject 并添加 cancel 函数
return new Promise((resolve, reject) => {
executor(resolve, reject, resolve)
})
}
}
startBtn.addEventListener('click', () => {
console.log('wait...')
const cancelPromise = new CouldCancelPromise((resolve, reject, cancel) => {
const id = setTimeout(resolve, 3000, 'done')
cancelBtn.addEventListener('click', () => {
cancel('cancel')
clearInterval(id)
})
})
cancelPromise.then(result => {
console.log(result)
})
})
</script>也可以采用继承的形式(不推荐继承内置对象)
class CouldCancelPromise extends Promise {
constructor(executor) {
super((resolve, reject) => {
executor(resolve, reject, resolve);
});
}
}#期约进度,就如 fetch 的下载进度一样,大致代码如下
class ProgressPromise extends Promise {
constructor(executor) {
const notifyHandlers = [];
super((resolve, reject) => {
return executor(resolve, reject, progress => {
notifyHandlers.forEach(notify => {
notify(progress);
});
});
});
this.notifyHandlers = notifyHandlers;
}
notify = function (fun) {
this.notifyHandlers.push(fun);
return this;
};
}
const p = new ProgressPromise((resolve, reject, notify) => {
function getData(step) {
if (step < 5) {
notify(`${step * 20} %.........`);
setTimeout(getData, 1000, step + 1);
} else {
resolve('done');
}
}
getData(0);
});
p.notify(progress => {
console.log(progress);
});
p.then(res => {
console.log(res);
});
/*
20 %.........
40 %.........
60 %.........
80 %.........
done
*/#异步函数
#async
用于定义异步函数,只在异步函数内才能使用 await
#await
await 可以展平 thenable 对象
async function foo() {
const origin = 'xz';
const obj = {};
const thenable = {
then(callback) {
callback('thenable');
},
};
const p = Promise.resolve('resolve');
console.log(await origin, await obj, await thenable, await p);
await Promise.reject('reject');
console.log('end'); // 不执行
}
foo().catch(console.log);
// xz {} thenable resolve reject#实现 sleep
function sleep(delay) {
return new Promise(resolve => setTimeout(resolve, delay));
}
async function main() {
console.log(1);
await sleep(1000);
console.log(2);
}
main();