资讯专栏INFORMATION COLUMN

JavaScript 异步编程

lordharrd / 1607人阅读

摘要:下面我将介绍的基本用法以及如何在异步编程中使用它们。在没有发布之前,作为异步编程主力军的回调函数一直被人诟病,其原因有太多比如回调地狱代码执行顺序难以追踪后期因代码变得十分复杂导致无法维护和更新等,而的出现在很大程度上改变了之前的窘境。

前言

自己着手准备写这篇文章的初衷是觉得如果想要更深入的理解 JS,异步编程则是必须要跨过的一道坎。由于这里面涉及到的东西很多也很广,在初学 JS 的时候可能无法完整的理解这一概念,即使在现在来看还是有很多自己没有接触和理解到的知识点,但是为了跨过这道坎,我仍然愿意鼓起勇气用我已经掌握的部分知识尽全力讲述一下 JS 中的异步编程。如果我所讲的一些概念或术语有错误,请读者向我指出问题所在,我会立即纠正更改。

同步与异步

我们知道无论是在浏览器端还是在服务器 ( Node ) 端,JS 的执行都是在单线程下进行的。我们以浏览器中的 JS 执行线程为例,在这个线程中 JS 引擎会创建执行上下文栈,之后我们的代码就会作为执行上下文 ( 全局、函数、eval ) 像一系列任务一样在执行上下文栈中按照后进先出 ( LIFO ) 的方式依次执行。而同步最大的特性就是会阻塞后面任务的执行,比如此时 JS 正在执行大量的计算,这个时候就会使线程阻塞从而导致页面渲染加载不连贯 ( 在浏览器端的 Event Loop 中每次执行栈中的任务执行完毕后都会去检查并执行事件队列里面的任务直到队列中的任务为空,而事件队列中的任务又分为微队列与宏队列,当微队列中的任务执行完后才会去执行宏队列中的任务,而在微队列任务执行完到宏队列任务开始之前浏览器的 GUI 线程会执行一次页面渲染 ( UI rendering ),这也就解释了为什么在执行栈中进行大量的计算时会阻塞页面的渲染 ) 。

与同步相对的异步则可以理解为在异步操作完成后所要做的任务,它们通常以回调函数或者 Promise 的形式被放入事件队列,再由事件循环 ( Event Loop ) 机制在每次轮询时检查异步操作是否完成,若完成则按事件队列里面的执行规则来依次执行相应的任务。也正是得益于事件循环机制的存在,才使得异步任务不会像同步任务那样完全阻塞 JS 执行线程。

异步操作一般包括 网络请求文件读取数据库处理

异步任务一般包括 setTimout / setIntervalPromiserequestAnimationFrame ( 浏览器独有 )setImmediate ( Node 独有 )process.nextTick ( Node 独有 )etc ...

注意: 在浏览器端与在 Node 端的 Event Loop 机制是有所不同的,下面给出的两张图简要阐述了在不同环境下事件循环的运行机制,由于 Event Loop 不是本文内容的重点,但是 JS 异步编程又是建立在它的基础之上的,故在下面给出相应的阅读链接,希望能够帮助到有需要的读者。

浏览器端

Node 端

阅读链接

深入理解 JS 事件循环机制 ( 浏览器篇 )

深入理解 JS 事件循环机制 ( Node.js 篇 )

为异步而生的 JS 语法

回望历史,在最近几年里 ECMAScript 标准几乎每年都有版本的更新,也正是因为有像 ES6 这种在语言特性上大版本的更新,到了现今的 8102 年, JS 中的异步编程相对于那个只有回调函数的远古时代有了很大的进步。下面我将介绍 callback 、Promise 、generator 、async / await 的基本用法以及如何在异步编程中使用它们。

callback

回调函数并不算是 JS 中的语法但它却是解决异步编程问题中最常用的一种方法,所以在这里有必要提出来,下面举一个例子,大家看一眼就懂。

const foo = function (x, y, cb) {
    setTimeout(() => {
        cb(x + y)
    }, 2000)
}

// 使用 thunk 函数,有点函数柯里化的味道,在最后处理 callback。
const thunkify = function (fn) {
    return function () {
        let args = Array.from(arguments)
        return function (cb) {
            fn.apply(null, [...args, cb])
        }
    }
}

let fooThunkory = thunkify(foo)

let fooThunk1 = fooThunkory(2, 8)
let fooThunk2 = fooThunkory(4, 16)

fooThunk1((sum) => {
    console.log(sum) // 10
})

fooThunk2((sum) => {
    console.log(sum) // 20
})
Promise

在 ES6 没有发布之前,作为异步编程主力军的回调函数一直被人诟病,其原因有太多比如回调地狱、代码执行顺序难以追踪、后期因代码变得十分复杂导致无法维护和更新等,而 Promise 的出现在很大程度上改变了之前的窘境。话不多说先直接上代码提前感受下它的魅力,然后我再总结下自己认为在 Promise 中很重要的几个点。

const foo = function () {
    let args = [...arguments]
    let cb = args.pop()
    setTimeout(() => {
        cb(...args)
    }, 2000)
}

const promisify = function (fn) {
    return function () {
        let args = [...arguments]
        return function (cb) {
            return new Promise((resolve, reject) => {
                fn.apply(null, [...args, resolve, reject, cb])
            })
        }
    }
}

const callback = function (x, y, isAdd, resolve, reject) {
    if (isAdd) {
        resolve(x + y)
    } else {
        reject("Add is not allowed.")
    }
}

let promisory = promisify(foo)

let p1 = promisory(4, 16, false)
let p2 = promisory(2, 8, true)

p1(callback)
.then((sum) => {
    console.log(sum)
}, (err) => {
    console.error(err) // Add is not allowed.
})
.finally(() => {
    console.log("Triggered once the promise is settled.")
})

p2(callback)
.then((sum) => {
    console.log(sum) // 10
    return "evil            
               
                                           
                       
                 

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/98528.html

相关文章

  • ES6-7

    摘要:的翻译文档由的维护很多人说,阮老师已经有一本关于的书了入门,觉得看看这本书就足够了。前端的异步解决方案之和异步编程模式在前端开发过程中,显得越来越重要。为了让编程更美好,我们就需要引入来降低异步编程的复杂性。 JavaScript Promise 迷你书(中文版) 超详细介绍promise的gitbook,看完再不会promise...... 本书的目的是以目前还在制定中的ECMASc...

    mudiyouyou 评论0 收藏0
  • Javascript中的异步编程

    摘要:接下来,我们一起来看看中的异步编程,具体有哪几种。实现异步编程的方法一回调函数上面不止一次提到了回调函数。它是异步编程中,最基本的方法。四对象接下来,我们聊聊与相关的异步编程方法,对象。 showImg(https://segmentfault.com/img/bVbneWy?w=1600&h=1200); 前言 最近,小伙伴S 问了我一段代码: const funB = (value...

    wemall 评论0 收藏0
  • JavaScript 异步

    摘要:从最开始的到封装后的都在试图解决异步编程过程中的问题。为了让编程更美好,我们就需要引入来降低异步编程的复杂性。写一个符合规范并可配合使用的写一个符合规范并可配合使用的理解的工作原理采用回调函数来处理异步编程。 JavaScript怎么使用循环代替(异步)递归 问题描述 在开发过程中,遇到一个需求:在系统初始化时通过http获取一个第三方服务器端的列表,第三方服务器提供了一个接口,可通过...

    tuniutech 评论0 收藏0
  • 浅析JavaScript异步

    摘要:回调函数,一般在同步情境下是最后执行的,而在异步情境下有可能不执行,因为事件没有被触发或者条件不满足。同步方式请求异步同步请求当请求开始发送时,浏览器事件线程通知主线程,让线程发送数据请求,主线程收到 一直以来都知道JavaScript是一门单线程语言,在笔试过程中不断的遇到一些输出结果的问题,考量的是对异步编程掌握情况。一般被问到异步的时候脑子里第一反应就是Ajax,setTimse...

    Tangpj 评论0 收藏0
  • JavaScript异步编程解决方案笔记

    摘要:异步编程解决方案笔记最近读了朴灵老师的深入浅出中异步编程一章,并参考了一些有趣的文章。另外回调函数中的也失去了意义,这会使我们的程序必须依赖于副作用。 JavaScript 异步编程解决方案笔记 最近读了朴灵老师的《深入浅出NodeJS》中《异步编程》一章,并参考了一些有趣的文章。在此做个笔记,记录并巩固学到的知识。 JavaScript异步编程的两个核心难点 异步I/O、事件驱动使得...

    dmlllll 评论0 收藏0
  • 夯实基础-JavaScript异步编程

    摘要:调用栈被清空,消息队列中并无任务,线程停止,事件循环结束。不确定的时间点请求返回,将设定好的回调函数放入消息队列。调用栈执行完毕执行消息队列任务。请求并发回调函数执行顺序无法确定。 异步编程 JavaScript中异步编程问题可以说是基础中的重点,也是比较难理解的地方。首先要弄懂的是什么叫异步? 我们的代码在执行的时候是从上到下按顺序执行,一段代码执行了之后才会执行下一段代码,这种方式...

    shadowbook 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<