一、异步函数调用:
//例子:一个名为 createAudioFileAsync() 的函数,它接收一些配置和两个回调函数,然后异步地生成音频文件。一个回调函数在文件成功创建时被调用,另一个则在出现异常时被调用
方法1、
// 成功的回调函数 function successCallback(result) { console.log("音频文件创建成功: " + result); } // 失败的回调函数 function failureCallback(error) { console.log("音频文件创建失败: " + error); } createAudioFileAsync(audioSettings, successCallback, failureCallback)
方法2、
/* *更现代的函数会返回一个 Promise 对象,使得你可以将你的回调函数绑定在该 Promise 上 *如果函数 createAudioFileAsync() 被重写为返回 Promise 的形式,那么我们可以像下面这样简单地调用它 */ const aa = createAudioFileAsync(audioSettings); aa.then(successCallback, failureCallback); //简写 createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
二、链式调用:
//连续执行两个或者多个异步操作时,在上一个操作执行成功后带着返回的结果,开始下一个操作 ,可用Promise链来实现(解决地狱回调问题)
1)地狱回调:
doSomething( function(result){
doSomethingElse(result, function(newResult) {
doThirdThing(newResult, function(finalResult){
console.log('Go the final result :'+finalResult);
},failureCallbake)
},failureCallbake)
},failureCallbake)
2)Promis链
doSomething().then(function(result){
return doSomethingElse(result);
})
.then(function(newResult){
return doThirdThing(newResult);
})
.then(function(finalResult){
console.log('Go the final result:' + finalResult);
})
.catch(failureCallback);
//简写:then 里的参数是可选的,catch(failureCallback) 是 then(null, failureCallback) 的缩略形式
doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => {
console.log(`Got the final result: ${finalResult}`);
})
.catch(failureCallback);
//一定要有返回值,否则,callback 将无法获取上一个 Promise 的结果
三、Catch的后续链式操作
使用一个 catch,
在链式操作中抛出一个失败之后,再次进行新的操作
new Promise((resolve, reject) => { console.log('初始化'); resolve(); }) .then(() => { throw new Error('有哪里不对了'); console.log('执行「这个1」”'); }) .catch(() => { console.log('执行「那个」'); }) .then(() => { console.log('执行「这个2」,无论前面发生了什么'); }); /* *控制台输出: * 初始化 * 执行「那个」 * 执行「这个2」,无论前面发生了什么 * *注意:因为抛出了错误 有哪里不对了,所以前一个 执行「这个」 没有被输出 */
四、错误传递:
1)通常情况下,一遇到异常抛出,浏览器就会顺着Promise 链寻找下一个由 .catch()
指定的回调函数或者onRejected
失败回调函数
//以上所述 的代码工作原理 try { let result = syncDoSomething(); let newResult = syncDoSomethingElse(result); let finalResult = syncDoThirdThing(newResult); console.log(`Got the final result: ${finalResult}`); } catch(error) { failureCallback(error); }
2) async/await
语法糖,异步代码
async function foo() { try { const result = await doSomething(); const newResult = await doSomethingElse(result); const finalResult = await doThirdThing(newResult); console.log(`Got the final result: ${finalResult}`); } catch(error) { failureCallback(error); } }
五、组合:
// 1) Promise.resolve() 和 Promise.reject() 是手动创建一个已经 resolve 或者 reject 的 Promise 快捷方法 // 2) Promise.all() 和 Promise.race() 是并行运行异步操作的两个组合式工具
1)发起多个操作,等多个操作全部结束后进行下一步操作:
Promise.all([func1(), func2(), func3()]) .then(([result1, result2, result3]) => { /* use result1, result2 and result3 进行下一步操作*/ });
2)用js实现时序组合:
[func1, func2, func3].reduce((p, f) => p.then(f), Promise.resolve()) .then(result3 => { /* use result3 */ });
3)递归调用一个由异步函数组成的数组时,相当于一个 Promise 链:
Promise.resolve().then(func1).then(func2).then(func3);
4)asnyc /await:
let result; for (const f of [func1, func2, func3]) { result = await f(result); } /* use last result (i.e. result3) */
六、嵌套:
嵌套 Promise 是一种可以限制 catch
语句的作用域的控制结构写法,就是嵌套的 catch
仅捕捉在其之前同时还必须是其作用域的 failureres,而捕捉不到在其链式以外或者其嵌套域以外的 error。
doSomethingCritical() .then(result => doSomethingOptional() .then(optionalResult => doSomethingExtraNice(optionalResult)) .catch(e => {console.log(e.message)})) // 即使有异常也会忽略,继续运行;(最后会输出) .then(() => moreCriticalStuff()) .catch(e => console.log("Critical failure: " + e.message));// 没有输出
//这个内部的catch
语句仅能捕获到doSomethingOptional()
和doSomethingExtraNice()
的失败,之后就恢复到moreCriticalStuff()
的运行。
//重要提醒:如果doSomethingCritical()
失败,这个错误仅会被最后的(外部)catch
语句捕获到。