广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >JavaScript异步编程操作实现介绍
  • 651
分享到

JavaScript异步编程操作实现介绍

2024-04-02 19:04:59 651人浏览 泡泡鱼
摘要

目录异步编程同步模式与异步模式同步模式(Synchronous)异步模式(Asynchronous)回调函数PromisePromise基本用法Promise使用案例Promise常

异步编程

目前主流的javascript执行环境都是以单线程执行JavaScript的。

JavaScript早期只是一门负责在浏览器端执行的脚本语言,主要用来操作DOM,如果其添加的同时又删除了DOM,浏览器就不知道该如何是好,所以其就被设计成为单线程模型。而随着JavaScript能做的事情越来越多,如果一直维持同步编程的话,就会导致浏览器卡在某个耗时操作无法进行下一步,造成浏览器假死的现象,影响用户体验。因此,异步编程应运而生。

同步模式与异步模式

同步模式(Synchronous)

同步模式是指代码是同步执行的,下一步的代码执行必须要等到上一步的代码完成之后才能执行,执行顺序就为代码的编写顺序。

console.log('global begin')
function bar() {
    console.log('bar task')
}
function foo() {
    console.log('foo task')
    bar()
}
foo()
console.log('global end')

异步模式(Asynchronous)

不会去等待这个任务的执行完成才去执行下一个任务,开启过后就立即开始下一个任务,后续逻辑一般会通过回调函数来进行定义。

console.log('global begin')
setTimeout(function timer1 () {
  console.log('timer1 invoke')
}, 1800)
setTimeout(function timer2 () {
  console.log('timer2 invoke')

  setTimeout(function inner () {
    console.log('inner invoke')
  }, 1000)
}, 1000)
console.log('global end')

回调函数

回调函数——所有异步编程方案的根基

其实回调函数就是封装你想要对某些数据进行的操作,等到你想要进行的操作结束后,再调用这个函数。

一讲起回调函数,面试中一般都会被问到,什么是回调地狱?如何解决回调地狱。以下面代码为例:

// 回调地狱,只是示例,不能运行
$.get('/url1', function (data1) {
  $.get('/url2', data1, function (data2) {
    $.get('/url3', data2, function (data3) {
      $.get('/url4', data3, function (data4) {
        $.get('/url5', data4, function (data5) {
          $.get('/url6', data5, function (data6) {
            $.get('/url7', data6, function (data7) {
              // 略微夸张了一点点
            })
          })
        })
      })
    })
  })
})

一大串的回调不仅难以阅读,当代码出现错误时,找出代码错误更是一种折磨。幸运的是,JavaScript是在不断发展的,在ES2015(es6)中,出现了一种解决方法,妈妈再也不用担心我写代码碰到回调地狱了。

Promise

Promise——一种更优的异步编程统一方案

你可以把Promise理解成“承诺”或者“期约”(js高程作者的翻译,想了解的话,可以去看看红宝书第四版),你已经声明了这个东西,它在未来的时间一定会执行,你可以相信它。

首先,你要了解Promise是有三种状态,即pending(等待)、onFulfilled(完成)、onRejected(失败),完成或失败状态一旦确定,就是无法更改的。

Promise基本用法

const promise = new Promise(function (resolve, reject) {
  // 注意,要得到reject的结果时要先把resolved的代码注释掉,原因上面已经解释了
  resolve(100)    // 兑现承诺
  reject(new Error('promise rejected'))   // 承诺失败
})
promise.then(function(value) {
  console.log('resolved', value)
}, function(error) {
  console.log('rejected', error)
})
console.log('end')

每个new Promise都接受两个参数,第一个为兑现承诺的函数,会将函数中的值传递给promise实例,reject等同。而返回的promise又自带一个then方法,也接受两个参数,一个代表成功的回调,一个代表失败的回调。

Promise使用案例

在当前文件夹下新建一个文件夹,其中随便放两个JSON文件,用来模拟ajax请求。

// Promise 方式的 AJAX
function ajax(url) {
  return new Promise(function(resolve, reject) {
    let xhr = new XMLHttpRequest()
    xhr.open('GET', url)
    xhr.responseType = 'json'
    xhr.onload = function() {
      if (this.status === 200) {
        resolve(this.response)
      } else {
        reject(new Error(this.statusText))
      }
    }
    xhr.send()
  })
}
ajax('./api/posts.json').then(function (res) {
  console.log(res)
}, function(err) {
  console.log(err)
})

注意,上述代码应该在浏览器端运行。

Promise常见误区

有人学了promise之后,可能还是会写出这样的代码:

ajax('/api/urls.json').then(function (urls) {
  ajax(urls.users).then(function (users) {
    ajax(urls.users).then(function (users) {
      ajax(urls.users).then(function (users) {
        ajax(urls.users).then(function (users) {
        })
      })
    })
  })
})

说实话,这样写还不如不写。正经写法是链式调用,学过Jquery的同学应该不会陌生吧。

ajax('/api/users.json')
  .then(function (value) {
    console.log(1111)
    return ajax('/api/urls.json')
  }) // => Promise
  .then(function (value) {
    console.log(2222)
    console.log(value)
    return ajax('/api/urls.json')
  }) // => Promise
  .then(function (value) {
    console.log(3333)
    return ajax('/api/urls.json')
  }) // => Promise
  .then(function (value) {
    console.log(4444)
    return 'foo'
  }) // => Promise
  .then(function (value) {
    console.log(5555)
    console.log(value)
  })

Promise异常处理

通过.catch方法来捕获异常。

ajax('/api/users.json')
  .then(function onFulfilled (value) {
    console.log('onFulfilled', value)
    return ajax('/error-url')
  })
  .catch(function onRejected (error) {
    console.log('onRejected', error)
  })

其实catch方法和then方法实现差不太多,不过是then方法第一个参数传入undefine,一个语法糖而已。还有一个有意思的现象是,当中间的then出现错误时,会直接穿透到最后的catch方法,有兴趣了解怎么实现的可以去看看源码。相信你一定会有所收获。

Promise静态方法

  • Promise.resolve
Promise.resolve('foo')
  .then(function (value) {
    console.log(value)
  })

该方法会直接将传入的内容当作一个onFulfilled对象返回;其也可以传入一个Promise对象,直接返回Promise.resolve方法;传入一个带有then方法的函数也同理。

  • Promise.reject

该方法和上述一样调用,不过后面是接一个catch。

  • Promise.all

该方法接受一个数组,会等待数组内的方法全部调用完后再返回一个数组对象。

  • Promise.race

该方法会返回最先完成的promise。

宏任务与微任务

// 微任务
console.log('global start')
// setTimeout 的回调是 宏任务,进入回调队列排队
setTimeout(() => {
  console.log('setTimeout')
}, 0)
// Promise 的回调是 微任务,本轮调用末尾直接执行
Promise.resolve()
  .then(() => {
    console.log('promise')
  })
  .then(() => {
    console.log('promise 2')
  })
  .then(() => {
    console.log('promise 3')
  })
console.log('global end')

每次调用宏任务之前,都得确保微任务队列清空,所以也就能理解上面为什么会按照那样的顺序进行输出。

常见的宏任务有

  • setTimeout
  • setInterval
  • setImmediate
  • I/O
  • UI rendering

常见的微任务有

  • promise
  • nextTick
  • mutationObserver

Generator 异步方案

ES6也推出了Generator异步解决方案。首先来看下生成器函数如何使用。

生成器函数回顾

function *foo() {
  console.log('satrt')
  try {
    const res = yield 'foo'
    console.log(res)
  } catch (e) {
    console.log(e)
  }
}
const generator = foo()
const result = generator.next()
console.log(result)
generator.throw(new Error('Generato error'))

生成器函数比普通函数多了个 * ,其放左放右都无所谓,我个人倾向于放右边。

其内部有一个next方法,返回一个对象,大概就是这个样子

{ value: 'foo', done: false }

value为yield返回的值,当然,如果你调用yield时传入了值,返回的值就是你传入的值。当执行完毕时,done就变成了true。

function * main () {
  try {
    const users = yield ajax('/api/users.json')
    console.log(users)
    const posts = yield ajax('/api/posts.json')
    console.log(posts)
    const urls = yield ajax('/api/urls11.json')
    console.log(urls)
  } catch (e) {
    console.log(e)
  }
}
function co (generator) {
  const g = generator()
  function handleResult (result) {
    if (result.done) return // 生成器函数结束
    result.value.then(data => {
      handleResult(g.next(data))
    }, error => {
      g.throw(error)
    })
  }
  handleResult(g.next())
}
co(main)

你只要理解了这个,即要通过你调用next方法才会进行到下一步,否则代码就会停在yield那里。不过,你这样每次享受优美代码时都还是需要自己编写一个co函数,未免有点太过麻烦。不过不用担心,async就要出场了。

async与await

async、await——可能是异步的终极解决方案

async function main () {
  try {
    const users = await ajax('/api/users.json')
    console.log(users)
    const posts = await ajax('/api/posts.json')
    console.log(posts)
    const urls = await ajax('/api/urls.json')
    console.log(urls)
  } catch (e) {
    console.log(e)
  }
}

你只需要在函数定义前加一个async,并在你想要等待的完成操作后的函数前加一个await,就可以实现同步的书写代码而异步调用,怎么样?这是不是更加优雅方便了呢?鉴于目前ECMAScript的发展趋势,保不准哪一天不需要async,直接用await就能实现异步编程了。

到此这篇关于JavaScript异步编程操作实现介绍的文章就介绍到这了,更多相关JS异步编程内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: JavaScript异步编程操作实现介绍

本文链接: https://www.lsjlt.com/news/167192.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • JavaScript异步编程操作实现介绍
    目录异步编程同步模式与异步模式同步模式(Synchronous)异步模式(Asynchronous)回调函数PromisePromise基本用法Promise使用案例Promise常...
    99+
    2022-11-13
  • Javascript异步编程简介
    这篇文章主要介绍“Javascript异步编程简介”,在日常操作中,相信很多人在Javascript异步编程简介问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Javascri...
    99+
    2022-10-19
  • 异步编程之asyncio简单介绍
    引言: python由于GIL(全局锁)的存在,不能发挥多核的优势,其性能一直饱受诟病。然而在IO密集型的网络编程里,异步处理比同步处理能提升成百上千倍的效率,弥补了python性能方面的短板. asyncio是做什么的 异步网络操作 ...
    99+
    2023-01-30
    简单 asyncio
  • Node.js 异步编程之 Callback介绍(一)
    Node.js 基于 JavaScript 引擎 v8,是单线程的。Node.js 采用了与通常 Web 上的 JavaScript 异步编程的方式来处理会造成阻塞的I/O操作。在 Node.js 中读取文...
    99+
    2022-06-04
    Node js Callback
  • JavaScript函数式编程实现介绍
    目录为什么要学习函数式编程什么是函数式编程前置知识函数是一等公民函数可以储存在变量中函数作为参数函数作为返回值高阶函数什么是高阶函数使用高阶函数的意义常用高阶函数闭包纯函数纯函数概念...
    99+
    2022-11-13
  • Dubbo异步调用的实现介绍
    目录前言1、异步调用实现2、异步调用特殊说明前言 Dubbo不只提供了堵塞式的的同步调用,同时提供了异步调用的方式。这种方式主要应用于提供者接口响应耗时明显,消费者端可以利用调用接口...
    99+
    2022-11-13
  • .NET异步编程模式的三种类型介绍
    一、引言 .NET中很多的类、接口在设计的时候都考虑了多线程问题,简化了多线程程序的开发,不用自己去写WaitHandler等这些底层的代码,由于历史的发展,这些类的接口设计有着三种...
    99+
    2022-11-13
  • ES6中javascript如何实现异步操作
    这篇文章主要为大家展示了“ES6中javascript如何实现异步操作”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“ES6中javascript如何实现异步操作...
    99+
    2022-10-19
  • JavaScript对象合并实现步骤介绍
    JavaScript 中有多种方法可以合并对象。 1、使用 Object.assign() 方法: 它可以将一个或多个对象的属性复制到目标对象中。例如: const obj1 = {...
    99+
    2023-01-31
    JavaScript对象合并 JS对象合并
  • C++异步数据交换实现方法介绍
    异步数据交换,除了阻塞函数 send() 和 recv() 之外,Boost.MPI 还支持与成员函数 isend() 和 irecv() 的异步数据交换。名称以 i 开头,表示函数...
    99+
    2022-11-21
    C++异步数据交换 C++数据交换
  • PHP中如何实现异步编程时的数组操作?
    在PHP中,数组是一个非常常见的数据结构,它可以用来存储一组相关的数据。在异步编程中,对数组的操作也是非常常见的。本文将介绍PHP中如何实现异步编程时的数组操作。 1.使用swoole的协程 在PHP中,可以使用swoole的协程来实现异...
    99+
    2023-10-30
    数组 异步编程 重定向
  • PHP异步编程技术:如何实现重定向操作?
    在Web开发中,重定向操作是非常常见的一种技术。它能够将用户从当前页面重定向到另一个页面,从而实现页面跳转。在PHP中,我们可以使用异步编程技术来实现重定向操作。本文将介绍如何使用PHP异步编程技术实现重定向操作,并附有相应的演示代码。 ...
    99+
    2023-06-20
    异步编程 重定向 开发技术
  • Go编程:如何通过重定向实现异步操作?
    在Go语言中,我们可以通过重定向实现异步操作。重定向是指将输出流或错误流重定向到一个文件,而不是在终端输出。在Go语言中,我们可以使用os包和io包来实现这一功能。 下面是一个简单的例子,演示如何通过重定向实现异步操作: package ...
    99+
    2023-07-23
    异步编程 重定向 学习笔记
  • Flutter异步操作实现流程详解
    目录一、FutureBuilder二、StreamBuilder在Flutter中,借助 FutureBuilder 组件和 StreamBuilder 组件,可以非常方便地完成异步...
    99+
    2022-11-13
  • ASP异步编程和Laravel响应:如何在Web应用中实现异步操作?
    在Web应用中,异步操作是非常重要的功能,特别是对于需要大量计算的任务,例如下载、上传、数据库查询等等。异步操作可以使得Web应用更加高效和快速,提高用户的体验和满意度。在本文中,我们将探讨ASP异步编程和Laravel响应,以及如何在W...
    99+
    2023-08-18
    异步编程 laravel 响应
  • 异步编程:PHP和NumPy的文件操作实践。
    异步编程是现代计算机编程领域的一个重要议题,它可以大大提高程序运行效率和响应速度。在本文中,我们将探讨PHP和NumPy两个编程语言下异步编程在文件操作方面的实践。 一、PHP异步文件操作 PHP是一种广泛使用的服务器端脚本语言,它具有易学...
    99+
    2023-10-05
    numpy 异步编程 文件
  • JavaScript中实现异步编程模式的方法
    小编给大家分享一下JavaScript中实现异步编程模式的方法,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!JavaScript中实现异步编程模式的方法:1、回调函数,这是异步编程最基本的方法;2、事件监听;3、发布或订阅...
    99+
    2023-06-14
  • python中Event实现线程间同步介绍
    前言: Event在python线程间同步是一种常用的方法,本博客以生产者线程和工作者线程为例说明Event在线程间进行10次同步的应用。 import threading from...
    99+
    2022-11-10
  • C#如何实现异步操作
    这篇文章给大家分享的是有关C#如何实现异步操作的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。.NET Framework 为异步操作提供了两种设计模式:使用 IAsyncResult 对象的异步操作与使用事件的异...
    99+
    2023-06-18
  • PHP怎么实现异步操作
    这篇文章主要讲解了“PHP怎么实现异步操作”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PHP怎么实现异步操作”吧!1.为啥PHP需要异步操作?一般来说PHP适用的场合是web页面展示等耗时...
    99+
    2023-06-04
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作