0

0

JavaScript中的异步处理解析

小云云

小云云

发布时间:2017-12-04 11:32:12

|

1957人浏览过

|

来源于php中文网

原创

异步处理就是按照不同步的程序处理问题。异步处理与同步处理是对立的,而产生他们的是多线程或者多进程。异步处理的好处就是提高设备使用率,从而在宏观上提升程序运行效率,但是弊端就是容易出现冲突操作和数据脏读。本文我们就和大家分享关于javascript中的异步处理。

在 JavaScript 的世界中,所有代码都是单线程执行的。由于这个“缺陷”,导致 JavaScript 的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现

异步操作会在将来的某个时间点触发一个函数调用

主流的异步处理方案主要有:回调函数 (CallBack) 、 Promise 、 Generator 函数、 async/await 。

一、回调函数(CallBack)

立即学习Java免费学习笔记(深入)”;

这是异步编程最基本的方法

假设我们有一个 getData 方法,用于异步获取数据,第一个参数为请求的 url 地址,第二个参数是回调函数,如下:

function getData(url, callBack){    // 模拟发送网络请求
    setTimeout(()=> {        // 假设 res 就是返回的数据
        var res = {
            url: url,
            data: Math.random()
        }        // 执行回调,将数据作为参数传递
        callBack(res)
    }, 1000)
}

我们预先设定一个场景,假设我们要请求三次服务器,每一次的请求依赖上一次请求的结果,如下:

getData('/page/1?param=123', (res1) => {    console.log(res1)
    getData(`/page/2?param=${res1.data}`, (res2) => {        console.log(res2)
        getData(`/page/3?param=${res2.data}`, (res3) => {            console.log(res3)
        })
    })
})

通过上面的代码可以看出,第一次请求的 url 地址为: /page/1?param=123 ,返回结果为 res1 。

第二个请求的 url 地址为: /page/2?param=${res1.data} ,依赖第 一次请求的 res1.data ,返回结果为 res2`。

第三次请求的 url 地址为: /page/3?param=${res2.data} ,依赖第二次请求的 res2.data ,返回结果为 res3 。

由于后续请求依赖前一个请求的结果,所以我们只能把下一次请求写到上一次请求的回调函数内部,这样就形成了常说的:回调地狱。

二、发布/订阅

我们假定,存在一个”信号中心”,某个任务执行完成,就向信号中心”发布”( publish )一个信号,其他任务可以向信号中心”订阅”( subscribe )这个信号,从而知道什么时候自己可以开始执行。这就叫做”发布/订阅模式”(publish-subscribe pattern),又称”观察者模式”(observer pattern)

这个模式有多种实现,下面采用的是Ben Alman的 Tiny Pub/Sub ,这是 jQuery 的一个插件

首先, f2 向”信号中心” jQuery 订阅” done “信号

jQuery.subscribe("done", f2);
f1进行如下改写
function f1(){                setTimeout(function(){                        // f1的任务代码                        jQuery.publish("done");                }, 1000);}
jQuery.publish("done") 的意思是, f1 执行完成后,向”信号中心 "jQuery 发布 "done" 信号,从而引发f2的执行。 此外,f2完成执行后,也可以取消订阅( unsubscribe )
jQuery.unsubscribe("done", f2);

这种方法的性质与”事件监听”类似,但是明显优于后者。因为我们可以通过查看”消息中心”,了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。

三、Promise

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大

所谓 Promise ,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说, Promise 是一个对象,从它可以获取异步操作的消息。 Promise 提供统一的 API ,各种异步操作都可以用同样的方法进行处理

简单说,它的思想是,每一个异步任务返回一个 Promise 对象,该对象有一个 then 方法,允许指定回调函数。

现在我们使用 Promise 重新实现上面的案例,首先,我们要把异步请求数据的方法封装成 Promise

function getDataAsync(url){    return new Promise((resolve, reject) => {
        setTimeout(()=> {            var res = {
                url: url,
                data: Math.random()
            }
            resolve(res)
        }, 1000)
    })
}

那么请求的代码应该这样写

getDataAsync('/page/1?param=123')
    .then(res1=> {        console.log(res1)        return getDataAsync(`/page/2?param=${res1.data}`)
    })
    .then(res2=> {        console.log(res2)        return getDataAsync(`/page/3?param=${res2.data}`)
    })
    .then(res3=> {        console.log(res3)
    })

then 方法返回一个新的 Promise 对象, then 方法的链式调用避免了 CallBack 回调地狱

ShoopD 网上商店系统
ShoopD 网上商店系统

用 php + mysql 驱动的在线商城系统,我们的目标为中国的中小企业及个人提供最简洁,最安全,最高效的在线商城解决方案,使用了自建的会员积分折扣功能,不同的会员组有不同的折扣,让您的商店吸引更多的后续客户。 系统自动加分处理功能,自动处理会员等级,免去人工处理的工作量,让您的商店运作起来更方便省事 采用了自建的直接模板技术,免去了模板解析时间,提高了代码利用效率 独立开发的购物车系统,使用最

下载

但也并不是完美,比如我们要添加很多 then 语句, 每一个 then 还是要写一个回调。

如果场景再复杂一点,比如后边的每一个请求依赖前面所有请求的结果,而不仅仅依赖上一次请求的结果,那会更复杂。 为了做的更好, async/await 就应运而生了,来看看使用 async/await 要如何实现

四、async/await

getDataAsync 方法不变,如下

function getDataAsync(url){    return new Promise((resolve, reject) => {
        setTimeout(()=> {            var res = {
                url: url,
                data: Math.random()
            }
            resolve(res)
        }, 1000)
    })
}

业务代码如下

async function getData(){    var res1 = await getDataAsync('/page/1?param=123')    console.log(res1)    var res2 = await getDataAsync(`/page/2?param=${res1.data}`)    console.log(res2)    var res3 = await getDataAsync(`/page/2?param=${res2.data}`)    console.log(res3)
}

可以看到使用 async\await 就像写同步代码一样

对比 Promise 感觉怎么样?是不是非常清晰,但是 async/await 是基于 Promise 的,因为使用 async 修饰的方法最终返回一个 Promise , 实际上, async/await 可以看做是使用 Generator 函数处理异步的语法糖,我们来看看如何使用 Generator 函数处理异步

五、Generator

首先异步函数依然是

function getDataAsync(url){    return new Promise((resolve, reject) => {
        setTimeout(()=> {            var res = {
                url: url,
                data: Math.random()
            }
            resolve(res)
        }, 1000)
    })
}

使用 Generator 函数可以这样写

function*getData(){    var res1 = yield getDataAsync('/page/1?param=123')   
 console.log(res1)    var res2 = yield getDataAsync(`/page/2?param=${res1.data}`)   
  console.log(res2)    var res3 = yield getDataAsync(`/page/2?param=${res2.data}`)    console.log(res3))
}

然后我们这样逐步执行

var g = getData()
g.next().value.then(res1=> {
    g.next(res1).value.then(res2=> {
        g.next(res2).value.then(()=> {
            g.next()
        })
    })
})

上面的代码,我们逐步调用遍历器的 next() 方法,由于每一个 next() 方法返回值的 value 属性为一个 Promise 对象

所以我们为其添加 then 方法, 在 then 方法里面接着运行 next 方法挪移遍历器指针,直到 Generator 函数运行完成,实际上,这个过程我们不必手动完成,可以封装成一个简单的执行器

function run(gen){    var g = gen()    function next(data){        var res = g.next(data)        if (res.done) return res.value
        res.value.then((data) => {
            next(data)
        })
    }
    next()
}

run 方法用来自动运行异步的 Generator 函数,其实就是一个递归的过程调用的过程。这样我们就不必手动执行 Generator 函数了。 有了 run 方法,我们只需要这样运行 getData 方法

run(getData)

这样,我们就可以把异步操作封装到 Generator 函数内部,使用 run 方法作为 Generator 函数的自执行器,来处理异步。其实我们不难发现, async/await 方法相比于 Generator 处理异步的方式,有很多相似的地方,只不过 async/await 在语义化方面更加明显,同时 async/await 不需要我们手写执行器,其内部已经帮我们封装好了,这就是为什么说 async/await 是 Generator 函数处理异步的语法糖了

以上内容就是关于JavaScript中的异步处理,希望能帮助到大家。

相关推荐:

PHP异步处理的实现方案

详谈 Jquery Ajax异步处理Json数据

php 异步处理

相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
C++ 设计模式与软件架构
C++ 设计模式与软件架构

本专题深入讲解 C++ 中的常见设计模式与架构优化,包括单例模式、工厂模式、观察者模式、策略模式、命令模式等,结合实际案例展示如何在 C++ 项目中应用这些模式提升代码可维护性与扩展性。通过案例分析,帮助开发者掌握 如何运用设计模式构建高质量的软件架构,提升系统的灵活性与可扩展性。

14

2026.01.30

c++ 字符串格式化
c++ 字符串格式化

本专题整合了c++字符串格式化用法、输出技巧、实践等等内容,阅读专题下面的文章了解更多详细内容。

9

2026.01.30

java 字符串格式化
java 字符串格式化

本专题整合了java如何进行字符串格式化相关教程、使用解析、方法详解等等内容。阅读专题下面的文章了解更多详细教程。

12

2026.01.30

python 字符串格式化
python 字符串格式化

本专题整合了python字符串格式化教程、实践、方法、进阶等等相关内容,阅读专题下面的文章了解更多详细操作。

4

2026.01.30

java入门学习合集
java入门学习合集

本专题整合了java入门学习指南、初学者项目实战、入门到精通等等内容,阅读专题下面的文章了解更多详细学习方法。

20

2026.01.29

java配置环境变量教程合集
java配置环境变量教程合集

本专题整合了java配置环境变量设置、步骤、安装jdk、避免冲突等等相关内容,阅读专题下面的文章了解更多详细操作。

18

2026.01.29

java成品学习网站推荐大全
java成品学习网站推荐大全

本专题整合了java成品网站、在线成品网站源码、源码入口等等相关内容,阅读专题下面的文章了解更多详细推荐内容。

19

2026.01.29

Java字符串处理使用教程合集
Java字符串处理使用教程合集

本专题整合了Java字符串截取、处理、使用、实战等等教程内容,阅读专题下面的文章了解详细操作教程。

3

2026.01.29

Java空对象相关教程合集
Java空对象相关教程合集

本专题整合了Java空对象相关教程,阅读专题下面的文章了解更多详细内容。

6

2026.01.29

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 4.4万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 2.6万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号