当前位置:网站首页 > Vue.js开发 > 正文

js中的同步与异步的理解

一,正常情况下同步代码

通常情况下,我们的代码执行顺序是从上到下,按照顺序执行。

console.log('1'); const a = test(); console.log(a); function test() { 
    console.log('2'); return '函数返回'; } console.log('3'); 

这个代码片段的返回结果是:

12,函数返回,3 

二,有异步的代码执行情况

console.log('1'); const a = test(); console.log(a); function test() { 
    setTimeout(() => { 
    //setTimeout是异步操作 console.log('2'); return '函数返回'; }, 1000); } console.log('3'); 

这个代码片段的执行结果便是:

1,undefined,3,2 

三,总结原因-同步阻塞与异步非阻塞

因为js是单线程机制的,所有的操作都必须一个一个来,如果中间有一个操作非常耗时,那整个线程都会阻塞在那里,这就是同步阻塞
为了解决这个问题,js引入了事件和回调函数机制,对于一个IO操作,比如一个ajax,当发出一个异步请求后,程序不会阻塞在那里等待结果的返回,而是继续执行下面的代码。当请求成功获取到结果后,就会调用回调函数来处理后面的事情,这个就是异步非阻塞
具体这个概念可以看我之前的文章:js中的同步与异步的理解

对应于一中正常的代码,就是同步阻塞,等一行代码执行完毕后才能执行下一行代码。 对应于二中的异步的代码,就是异步非阻塞,发现是异步后,不会阻塞住,而是继续执行后续的代码,等异步结果出来后,再执行。 

四,回调函数的产生和应用

有时候,我们需要在异步操作后再进行某些操作。于是可以在异步操作后再调用一个函数,利用的就是异步操作结果出来后,其内部代码顺序执行的原理:

console.log('1'); test(callback); function test(cb) { 
    setTimeout(() => { 
    //setTimeout是异步操作 const a = 2; cb(a); }, 1000); } function callback(val) { 
    console.log('回调函数执行', val); } console.log('3'); 执行结果:13,回调函数执行2 

如果第一个异步API执行的结果,需要给第二个异步api作为参数使用。但是第二个异步api在第一个异步api还没有执行完毕返回结果就执行了,那怎么办?

function asyncFn1(cb) { 
    setTimeout(() => { 
    console.log('这是第一个异步操作'); const a = 1; cb(a); }, 1000); } function asyncFn2(val) { 
    setTimeout(() => { 
    console.log('这是第二个异步操作', val); }, 2000); } asyncFn1(asyncFn2); 

五,promise的使用

引入promise的最大作用,就是把异步操作的过程和结果做到了分离,可以用promise.then()来获取和处理异步操作的结果。

function asyncFn1() { 
    return new Promise((resolve, reject) => { 
    setTimeout(() => { 
    console.log('这是第一个异步操作', 222); const a = 1; resolve(a); }, 1000); }); } function asyncFn2(val) { 
    return new Promise((resolve, reject) => { 
    setTimeout(() => { 
    console.log('这是第二个异步操作', val); resolve(); }, 2000); }); } console.log('1111'); asyncFn1().then(res => { 
    asyncFn2(res); }); console.log('3333'); 

打印的结果将会是:

1111 3333 这是第一个异步操作 222 这是第二个异步操作 1 

可以参考这张图理解:在这里插入图片描述

主线程按顺序执行代码

1,执行console.log('1111'); 2,执行asyncFn1,遇到setTimeout发现是异步,注册一下 3,执行console.log('3333')(因为js是异步非阻塞,所以这里继续执行后面的代码) 4,第一个异步setTimeout执行完毕了, console.log('这是第一个异步操作', 222); 5,因为使用了promise,所以会等第一个异步执行完毕,才开始执行then中的第二个异步 

主要就是理解这句话,js是异步非阻塞的,同步执行,异步注册后等待执行完毕。promise可以将回调函数的处理转化成链式调用,做到异步操作和结果的分离。
需要注意的是,promise并不会产生阻塞效果,它只对它包裹的异步操作负责,只能够实现它包裹的异步操作执行完毕后,才会执行.then中的代码。所以这里console.log(‘3333’)会先执行。
换句话说,promise只是局部的,受用户控制的顺序执行,采用的方案是promise包裹异步操作,resolve()返回异步结果,然后.then中处理异步结果。

六,async和await

async和await就更进一步,它能够将promise中的异步转化为同步,也就是说,它能产生阻塞效果,等待它后面的代码执行完毕后才会继续往下执行。
值得注意的是,await后面必须是一个promise对象才可以。

function asyncFn1() { 
    return new Promise((resolve, reject) => { 
    setTimeout(() => { 
    console.log('这是第一个异步操作', 222); const a = 1; resolve(a); }, 1000); }); } function asyncFn2(val) { 
    return new Promise((resolve, reject) => { 
    setTimeout(() => { 
    console.log('这是第二个异步操作', val); resolve(); }, 2000); }); } console.log('1111'); const result = await asyncFn1(); await asyncFn2(result); console.log('3333'); 

执行的结果:

1111 这是第一个异步操作 222 这是第二个异步操作 1 3333 
到此这篇js中的同步与异步的理解的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!

版权声明


相关文章:

  • webpack5学习与实战-(六)-babel-loader解析js文件2024-12-02 08:36:10
  • vue2使用脚手架配置prettier报错:‘prettier/prettier‘: context.getPhysicalFilename is not a function2024-12-02 08:36:10
  • inquirer:命令行中与用户进行交互的js库2024-12-02 08:36:10
  • vue2项目中全局引入scss变量2024-12-02 08:36:10
  • js正则表达式--个人常用2024-12-02 08:36:10
  • vue中动画效果的实现2024-12-02 08:36:10
  • vue3开启eslint之后报错:error Parsing error: ‘>‘ expected2024-12-02 08:36:10
  • 模块化使用vuex2024-12-02 08:36:10
  • vue3的语法使用总结api2024-12-02 08:36:10
  • vue项目history路由的配置2024-12-02 08:36:10
  • 全屏图片