你对JavaScript中的异步函数和Promise对象有深入了解吗?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1732个文字,预计阅读时间需要7分钟。
目录+1、JS中的异步 1.1 同步 一般情况下,JS的代码都是同步执行,即按照代码顺序执行。 1.2 异步 异步代码通常指的是在代码执行过程中,不立即执行的代码块。它可以在不阻塞主线程的情况下执行,常见于网络请求、文件操作等场景。 1.3 回调函数解决异步问题 回调函数是一种常见的异步处理方式,通过将回调函数作为参数传递给异步操作,来处理异步操作完成后的结果。 1.4 回调地狱 随着异步操作的增加,回调嵌套层次会越来越深,形成回调地狱,导致代码可读性和可维护性降低。
2、Promise对象
2.1 Promise的基本使用 Promise对象是ES6引入的一个用于处理异步操作的新机制,它允许我们将异步操作的结果表示为一个对象。 2.2 async和await async和await是ES7引入的两个关键字,它们可以帮助我们更简洁地处理异步代码,避免回调地狱。总结+1、JS中的异步 1.1 同步 一般情况下,JS的代码都是同步执行,即按照代码顺序执行。 1.2 异步 异步代码通常指的是在代码执行过程中,不立即执行的代码块。它可以在不阻塞主线程的情况下执行,常见于网络请求、文件操作等场景。 1.3 回调函数解决异步问题 回调函数是一种常见的异步处理方式,通过将回调函数作为参数传递给异步操作,来处理异步操作完成后的结果。 1.4 回调地狱 随着异步操作的增加,回调嵌套层次会越来越深,形成回调地狱,导致代码可读性和可维护性降低。目录
- 1、JS中的异步
- 1.1 同步
- 1.2 异步
- 1.3 回调函数解决异步问题
- 1.4 回调地狱
- 2、Promise对象
- 2.1 Promise的基本使用
- 2.2 async 和 await
- 总结
1、JS中的异步
1.1 同步
一般情况下,js的代码都是自上而下顺序运行的。例如:
let res = ''; res = '获取到的结果!'; console.log(res);
结果:
很容易理解,我给res赋了新值,然后输出res。这就是js的同步执行,这里的同步,并不是一起执行的意思,而是在一个线程里顺序执行的意思。因为JavaScript是单线程,所以所有程序都应该在一个线程里运行。
1.2 异步
但是有的时候,我们获取
res的值是需要一点时间的,例如使用ajax向服务器发起请求,服务器响应以后返回结果,我们再将结果赋值给res。
这里使用setTimeout函数模拟数据请求,setTimeout也是一个异步函数。
let res = ''; setTimeout(()=>{ res = '获取到的结果!'; console.log('获取到结果了!',res); },3000); console.log('res',res);
可以看到,没有立刻获取到结果,而是3s后才获取到结果。
为什么会这样呢?
由于获取res它是一个异步操作,所以它会被分为两部分来执行,先调用setTimeout方法,然后把要执行的函数放到一个队列中。代码继续往下执行,当把所有的代码都执行完后,放到队列中的函数才会被执行。因为js的单线程机制,不允许它花费时间去等待异步函数的结果。
1.3 回调函数解决异步问题
既然异步函数的结果会再最后获取,那么我们就可以给异步函数中加一个回调函数,来处理获取到的数据。
let res = ''; setTimeout(()=>{ res = '获取到的结果!'; callback(); },3000); function callback(){ console.log('获取到结果了!',res); console.log('处理结果!'); } console.log('res', res);
现在console.log('res', res);仍然没有获取到res,但是我们已经不需要它了,我们获取res的就是为了处理它,而使用callback函数就可以达到目的了!
1.4 回调地狱
1.3了解了可以通过调用函数解决无法获取结果的问题,但是它仍然是存在缺点的,如果只获取一次结果,那还好。但是如果我们在获取结果之后,还需要利用获取的结果再进行异步操作,那么又需要嵌套一层,又需要一次异步操作,再嵌套一层……
setTimeout(function(){ console.log("first"); setTimeout(function(){ console.log("second"); setTimeout(function(){ console.log("third"); setTimeout(function(){ console.log("fourth"); },2000); },2000); },2000); },2000);
虽然上述代码会按照我们预期的方向运行,但是多层的嵌套让代码阅读和维护起来十分的困难。
2、Promise对象
2.1 Promise的基本使用
为了解决异步中的回调地狱问题,ES6引入了Promise对象,使得我们可以十分优雅地进行异步操作。
从语法上来说,Promise是一个对象,从它可以获取异步操作的消息。
let timeout = function(time){ return new Promise(function(resolve,reject){ setTimeout(function(){ resolve(); },time); }); } console.log("开始运行!"); timeout(2000).then(function(){ console.log("first"); return timeout(2000); }).then(function(){ console.log("second"); return timeout(2000); }).then(function(){ console.log("third"); return timeout(2000); }).then(function(){ console.log("fourth"); return timeout(2000); });
这样就解决了上述的回调地狱的问题。并且then也很容易理解,就是上一个异步函数执行完成后,接着要进行的操作。
同时Promise对象也可以通过resolve和reject传递参数:
let res = null; let timeout = function(time){ return new Promise(function(resolve,reject){ setTimeout(function(){ res = false; if(res){ resolve('res为true'); }else{ reject('res为false'); } },time); }); } timeout().then((res)=>{ console.log(res); }).catch((error)=>{ console.log(error); })
这样就可以根据res的值来确定结果了。resolve()对应then的结果,而reject()对应catch的结果。这在axios的请求操作中是十分常见的。
2.2 async 和 await
mdn描述如下:
async函数是使用async关键字声明的函数。 async函数是AsyncFunction构造函数的实例, 并且其中允许使用await关键字。async和await关键字让我们可以用一种更简洁的方式写出基于Promise的异步行为,而无需刻意地链式调用promise。
async和await的关系:
async函数可能包含0个或者多个await表达式。await表达式会暂停整个async函数的执行进程并出让其控制权,只有当其等待的基于promise的异步操作被兑现或被拒绝之后才会恢复进程。promise的解决值会被当作该await表达式的返回值。使用async / await关键字就可以在异步代码中使用普通的try / catch代码块。
function getProcessedData(url) { return downloadData(url) // 返回一个 promise 对象 .catch(e => { return downloadFallbackData(url) // 返回一个 promise 对象 }) .then(v => { return processDataInWorker(v); // 返回一个 promise 对象 }); }
使用async和await重写上述函数。
async function getProcessedData(url) { let v; try { v = await downloadData(url); } catch (e) { v = await downloadFallbackData(url); } return processDataInWorker(v); }
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注自由互联的更多内容!
本文共计1732个文字,预计阅读时间需要7分钟。
目录+1、JS中的异步 1.1 同步 一般情况下,JS的代码都是同步执行,即按照代码顺序执行。 1.2 异步 异步代码通常指的是在代码执行过程中,不立即执行的代码块。它可以在不阻塞主线程的情况下执行,常见于网络请求、文件操作等场景。 1.3 回调函数解决异步问题 回调函数是一种常见的异步处理方式,通过将回调函数作为参数传递给异步操作,来处理异步操作完成后的结果。 1.4 回调地狱 随着异步操作的增加,回调嵌套层次会越来越深,形成回调地狱,导致代码可读性和可维护性降低。
2、Promise对象
2.1 Promise的基本使用 Promise对象是ES6引入的一个用于处理异步操作的新机制,它允许我们将异步操作的结果表示为一个对象。 2.2 async和await async和await是ES7引入的两个关键字,它们可以帮助我们更简洁地处理异步代码,避免回调地狱。总结+1、JS中的异步 1.1 同步 一般情况下,JS的代码都是同步执行,即按照代码顺序执行。 1.2 异步 异步代码通常指的是在代码执行过程中,不立即执行的代码块。它可以在不阻塞主线程的情况下执行,常见于网络请求、文件操作等场景。 1.3 回调函数解决异步问题 回调函数是一种常见的异步处理方式,通过将回调函数作为参数传递给异步操作,来处理异步操作完成后的结果。 1.4 回调地狱 随着异步操作的增加,回调嵌套层次会越来越深,形成回调地狱,导致代码可读性和可维护性降低。目录
- 1、JS中的异步
- 1.1 同步
- 1.2 异步
- 1.3 回调函数解决异步问题
- 1.4 回调地狱
- 2、Promise对象
- 2.1 Promise的基本使用
- 2.2 async 和 await
- 总结
1、JS中的异步
1.1 同步
一般情况下,js的代码都是自上而下顺序运行的。例如:
let res = ''; res = '获取到的结果!'; console.log(res);
结果:
很容易理解,我给res赋了新值,然后输出res。这就是js的同步执行,这里的同步,并不是一起执行的意思,而是在一个线程里顺序执行的意思。因为JavaScript是单线程,所以所有程序都应该在一个线程里运行。
1.2 异步
但是有的时候,我们获取
res的值是需要一点时间的,例如使用ajax向服务器发起请求,服务器响应以后返回结果,我们再将结果赋值给res。
这里使用setTimeout函数模拟数据请求,setTimeout也是一个异步函数。
let res = ''; setTimeout(()=>{ res = '获取到的结果!'; console.log('获取到结果了!',res); },3000); console.log('res',res);
可以看到,没有立刻获取到结果,而是3s后才获取到结果。
为什么会这样呢?
由于获取res它是一个异步操作,所以它会被分为两部分来执行,先调用setTimeout方法,然后把要执行的函数放到一个队列中。代码继续往下执行,当把所有的代码都执行完后,放到队列中的函数才会被执行。因为js的单线程机制,不允许它花费时间去等待异步函数的结果。
1.3 回调函数解决异步问题
既然异步函数的结果会再最后获取,那么我们就可以给异步函数中加一个回调函数,来处理获取到的数据。
let res = ''; setTimeout(()=>{ res = '获取到的结果!'; callback(); },3000); function callback(){ console.log('获取到结果了!',res); console.log('处理结果!'); } console.log('res', res);
现在console.log('res', res);仍然没有获取到res,但是我们已经不需要它了,我们获取res的就是为了处理它,而使用callback函数就可以达到目的了!
1.4 回调地狱
1.3了解了可以通过调用函数解决无法获取结果的问题,但是它仍然是存在缺点的,如果只获取一次结果,那还好。但是如果我们在获取结果之后,还需要利用获取的结果再进行异步操作,那么又需要嵌套一层,又需要一次异步操作,再嵌套一层……
setTimeout(function(){ console.log("first"); setTimeout(function(){ console.log("second"); setTimeout(function(){ console.log("third"); setTimeout(function(){ console.log("fourth"); },2000); },2000); },2000); },2000);
虽然上述代码会按照我们预期的方向运行,但是多层的嵌套让代码阅读和维护起来十分的困难。
2、Promise对象
2.1 Promise的基本使用
为了解决异步中的回调地狱问题,ES6引入了Promise对象,使得我们可以十分优雅地进行异步操作。
从语法上来说,Promise是一个对象,从它可以获取异步操作的消息。
let timeout = function(time){ return new Promise(function(resolve,reject){ setTimeout(function(){ resolve(); },time); }); } console.log("开始运行!"); timeout(2000).then(function(){ console.log("first"); return timeout(2000); }).then(function(){ console.log("second"); return timeout(2000); }).then(function(){ console.log("third"); return timeout(2000); }).then(function(){ console.log("fourth"); return timeout(2000); });
这样就解决了上述的回调地狱的问题。并且then也很容易理解,就是上一个异步函数执行完成后,接着要进行的操作。
同时Promise对象也可以通过resolve和reject传递参数:
let res = null; let timeout = function(time){ return new Promise(function(resolve,reject){ setTimeout(function(){ res = false; if(res){ resolve('res为true'); }else{ reject('res为false'); } },time); }); } timeout().then((res)=>{ console.log(res); }).catch((error)=>{ console.log(error); })
这样就可以根据res的值来确定结果了。resolve()对应then的结果,而reject()对应catch的结果。这在axios的请求操作中是十分常见的。
2.2 async 和 await
mdn描述如下:
async函数是使用async关键字声明的函数。 async函数是AsyncFunction构造函数的实例, 并且其中允许使用await关键字。async和await关键字让我们可以用一种更简洁的方式写出基于Promise的异步行为,而无需刻意地链式调用promise。
async和await的关系:
async函数可能包含0个或者多个await表达式。await表达式会暂停整个async函数的执行进程并出让其控制权,只有当其等待的基于promise的异步操作被兑现或被拒绝之后才会恢复进程。promise的解决值会被当作该await表达式的返回值。使用async / await关键字就可以在异步代码中使用普通的try / catch代码块。
function getProcessedData(url) { return downloadData(url) // 返回一个 promise 对象 .catch(e => { return downloadFallbackData(url) // 返回一个 promise 对象 }) .then(v => { return processDataInWorker(v); // 返回一个 promise 对象 }); }
使用async和await重写上述函数。
async function getProcessedData(url) { let v; try { v = await downloadData(url); } catch (e) { v = await downloadFallbackData(url); } return processDataInWorker(v); }
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注自由互联的更多内容!

