可以访问 Promise 对象基础 对 Promise 进行了解,这里就不再赘述了。
Promises 承诺,你将会得到延期或长期运行任务的未来结果。承诺有两个渠道:第一个为结果,第二个为潜在的错误。要获取结果,您将回调函数作为 then 函数参数,要处理错误,您将回调函数提供为 catch 函数参数。Promise 的状态的改变是单向的,一次性的,一旦改变,状态就会凝固了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <!DOCTYPE html> <html>
<head> <meta charset="utf-8"> </head>
<body> <script type="text/javascript"> let p = new Promise((resolve, reject) => { setTimeout(function() { const result = Math.random(); result > 0.5 ? resolve(result) : reject('Lower than 0.5'); }, 2000); });
p.then(result => { console.log('success', result); }).catch(result => { console.log('fail', result); }); </script> </body>
</html>
|
Promise.all
Promise.all()
返回一个 promise 对象,接收一个 Promise 对象的数组作为参数,当这个数组里的所有 Promise 对象全部变为 resolved 的时候该 promise 对象的状态才为 resolved,如果其中一个 Promise 对象为 rejected 的话则该 promise 的状态为 rejected。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function timerPromisefy(delay) { return new Promise(resolve => { setTimeout(() => { resolve(delay); }, delay); }); }
Promise.all([ timerPromisefy(32), timerPromisefy(1), timerPromisefy(64), timerPromisefy(2), timerPromisefy(256), ]).then(results => { console.log(results); });
|
Promise.race
Promise.race()
使用方法和 Promise.all()
一样,接收一个 Promise 对象数组为参数,只要其中一个 Promise 对象变为 resolved 或 rejected 状态,执行后面的 then 或者 catch 回调函数。
Promise 的处理逻辑
Promise 的调用链有很多种情况,但总结起来就一句话: then 和 catch 都会返回一个 promise 对象,如果我们没有手动的返回 promise 对象,那么就会自动地把返回值封装为一个 resolved promise 对象返回。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| Promise.resolve() .then(() => { console.log(1); }) .then((x) => { console.log(2, x); return Promise.resolve(); }) .then(() => { console.log(3);
return new Promise((resolve, reject) => { setTimeout(() => { resolve(); }, 1000); }); }) .then(() => { console.log(4); return Promise.reject(); }) .then(() => { console.log(5); }, () => { console.log('Error 1'); }) .then(() => { console.log(6); throw 'thrown'; }) .then(() => { console.log(7); }) .catch((error) => { console.log('Error final', error); });
|
输出:
1 2 3 4 5 6 7
| 1 2 undefined 3 4 Error 1 6 Error final thrown
|
async and await
Async 和 await 的作用是简化 promise then 的链式调用,相当于语法糖,缺点是中间不能处理异常:
- await 必须在 async 函数中
- async 函数会被异步执行,但是 aync 函数内的代码阻塞执行
- async 函数返回 promise,如果返回的不是 promise 对象,则会自动把返回结果封装为 promise 返回
- await 只是 promise then 的简写,得到的结果为 then 的参数,即 promise resolve 的实参
- await 如果出错,可以使用 try catch 进行处理,也可以在 promise 的 catch 中处理
视频 https://www.bilibili.com/video/BV1xW411J7K6 对 async and await 介绍的不错,有兴趣的话可以看看。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| function get() { return new Promise((resolve, reject) => { setTimeout(() => { if (Date.now() % 2 === 0) { resolve('---get'); } else { reject(Error('--get fail')); } }, 1000); }); }
function post() { return new Promise((resolve, reject) => { setTimeout(() => { resolve('---post'); }, 500); }); }
async function handle() { console.log(1);
const result1 = await get(); console.log(result1);
console.log(2);
const result2 = await post(); console.log(result2);
console.log(3);
return 4; }
console.log('from');
handle() .then((x) => { console.log('after handle', x); }) .catch((error) => { console.log(error); });
console.log('to');
|
Vue 的 methods 中定义的函数也支持 async await,需要注意的是 created 和 mounted 不支持。
也可以使用自执行函数调用:
1 2 3 4 5 6 7 8 9 10 11 12 13
| (async () => { const r1 = await funP1(); const r2 = await funP2(r1); })();
(async () => { try { const r1 = await funP1(); const r2 = await funP2(r1); } catch (error) { } })();
|
防止回调地狱
当一个请求结束后再执行下一个请求,如果用 callback,层次会很深,用 Promise 只需要在链式的 then 中处理上一个 then 中返回的 promise 的结果,防止回调地狱,最后的 catch 处理所有 promise 的 reject,中间任何一个 promise 执行了 reject 就会中断后续操作,async and await 能够使得 promise then 的调用链更简洁。
例如修改用户头像的操作:
- 拍照: capture
- 裁剪图片: crop
- 压缩图片: compress
- 上传图片到服务器: upload
- 检测图片中是否有人脸: detectFace
- 有人脸则更新头像: updateAvatar
如果用回调的方式实现上面的代码,则结构可能为 (当对回调的结果要进行 if else 多种判断时,情况会更复杂):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| function capture(callback) { Camera.capture((blobImage) => { callback(blobImage); }) }
function crop(blobImage, callback) { Cropper.crop(blobImage, (croppedBlobImage) => { callback(croppedBlobImage); }) }
function compress(blobImage, callback) { Compressor.compress(blobImage, '200px', '200px', (compressedBlobImage) => { callback(compressedBlobImage); }) }
function upload(blobImage, callback) { ajax.post(blobImage).success((response) => { callback(response.imageUrl); }); }
function detectFace(imageUrl, callback) { ajax.get(imageUrl).success((response) => { callback(response.result); }) }
function updateAvatar(userId, imageUrl) { ajax.post(userId, imageUrl); }
capture((image) => { crop(image, (croppedBlobImage) => { compress(croppedBlobImage, (compressedBlobImage) => { upload(compressedBlobImage, (imageUrl) => { detectFace(imageUrl, (success) => { if (success) { updateAvatar(userId, imageUrl); } else { alert('没有检测到人脸'); } }); }); }); }); });
|
使用 promise 的结构可以为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| function capture() { return new Promise((resolve, reject) => { Camera.capture((blobImage) => { resolve(blobImage); }); }); }
function crop(blobImage) { return new Promise((resolve, reject) => { Cropper.crop(blobImage, (croppedBlobImage) => { resolve(croppedBlobImage); }); }); }
function compress(blobImage) { return new Promise((resolve, reject) => { Compressor.compress(blobImage, '200px', '200px', (compressedBlobImage) => { resolve(compressedBlobImage); }); }); }
function upload(blobImage) { return new Promise((resolve, reject) => { ajax.post(blobImage).success((response) => { resolve(response.imageUrl); }); }); }
function detectFace(imageUrl) { return new Promise((resolve, reject) => { ajax.get(imageUrl).success((response) => { if (response.result) { resolve(); } else { reject(); } }) }); }
function updateAvatar(userId, imageUrl) { return new Promise((resolve, reject) => { ajax.post(userId, imageUrl).success(() => { resolve(); }); }); }
capture() .then(blobImage => { return crop(blobImage); }) .then(croppedBlobImage => { return compress(croppedBlobImage); }) .then(compressedBlobImage => { return upload(compressedBlobImage); }) .then(imageUrl => { return detectFace(imageUrl); }) .then(imageUrl => { return updateAvatar(userId, imageUrl); }) .catch(error => { console.log(error); });
|
使用 async and await 简化上面 promise 的代码,看上去更简洁、逻辑更清晰:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| async function handle() { try { const image = await capture(); const croppedImage = await crop(image); const compressedImage = await compress(croppedImage); const imageUrl = await upload(compressedImage); await detectFace(imageUrl); await updateAvatar(imageUrl); } catch (error) { console.log(error); } }
handle();
|