资讯专栏INFORMATION COLUMN

javascript异步编程总结

yearsj / 2447人阅读

摘要:以下总结了异步编程的种方式回调函数回调函数异步编程的最基本的方式。由小组的成员在规范中提出,目的是为异步编程提供统一接口。结尾参考文章异步编程参考文章使用详解

前言

Javascript语言的执行环境是“单线程”。

单线程: 一次只能完成一个任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务。

单线程的好处是执行环境简单,坏处是在一些耗时的任务上会堵塞进程。比如读取一个大文件,线程卡在这个任务上,造成页面卡死。

那如何在读取文件的同时,又能查看图片,做一些其他的事呢?

这就到了“同步”和“异步”之争:
同步:后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的。
异步:每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。

举个栗子:
去餐厅吃饭
同步:大家依次排队,前一个人付完钱,等待领取食物。。。漫长等待。。。食物做好了,后一个人跟进。
异步:大家依次排队,前一个人付完钱,服务员给他一个餐牌,后一个人跟进。餐牌对应的食物做好了,再去领取。

以下总结了“异步编程”的4种方式:

1. 回调函数

回调函数:异步编程的最基本的方式。

下面通过样例作为演示:我们定义三个方法“做饭”(cook)、“吃饭”(eat),“洗碗”(wash)三个方法,它们是层层依赖的关系,下一步的的操作需要使用上一部操作的结果(这里使用 setTimeout 模拟异步操作)。

// 做饭
function cook() {
    console.log("开始做饭...");

    sleep(2000);   // 等待2秒

    console.log("做饭完毕");
}

// 吃饭
function eat() {
    console.log("开始吃饭...");

    sleep(2000);   // 等待2秒

    console.log("吃饭完毕");
}

// 洗碗
function wash() {
    console.log("开始洗碗...");

    sleep(2000);   // 等待2秒

    console.log("洗碗完毕");
}

// 阻塞等待(毫秒)
function sleep(delay) {
    let start = (new Date()).getTime();

    while((new Date()).getTime() - start < delay) {
        continue;
    }
}

cook();
eat();
wash();

// 开始做饭...
// 做饭完毕
// 开始吃饭...
// 吃饭完毕
// 开始洗碗...
// 洗碗完毕

上面是“同步”的写法,下面我们改写成“异步”:回调函数

// 做饭
function cook(callback) {
    console.log("开始做饭...");

    setTimeout(function() {
        console.log("做饭完毕");

        // 这里是回调,执行吃饭的方法
        callback();

    }, 2000);
}

// 吃饭
function eat(callback) {
    console.log("开始吃饭...");

    setTimeout(function() {
        console.log("吃饭完毕");

        // 这里是回调,执行洗碗的方法
        callback();
        
    }, 2000);
}

// 洗碗
function wash() {
    console.log("开始洗碗...");

    setTimeout(function() {
        console.log("洗碗完毕");

        // 洗碗之后的其他动作,这里就不写了

    }, 2000);
}

cook(function() {
    eat(function() {
        wash();
    })
});

// 开始做饭...
// 做饭完毕
// 开始吃饭...
// 吃饭完毕
// 开始洗碗...
// 洗碗完毕

回调函数的优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,各个部分之间高度耦合(Coupling),流程会很混乱,而且每个任务只能指定一个回调函数。

2. 事件监听

事件监听:采用事件驱动模式,任务的执行不取决于代码的顺序,而取决于某个事件是否发生。

let events = require("events");
let eventEmitter = new events.EventEmitter();

// 做饭
var cook = function() {
    console.log("开始做饭...");

    setTimeout(function() {
        console.log("做饭完毕");

        // 执行eat事件
        eventEmitter.emit("eatEvent");

    }, 2000);
}

// 吃饭
var eat = function() {
    console.log("开始吃饭...");

    setTimeout(function() {
        console.log("吃饭完毕");

        // 执行wash事件
        eventEmitter.emit("washEvent");

    }, 2000);
}

// 洗碗
var wash = function() {
    console.log("开始洗碗...");

    setTimeout(function() {
        console.log("洗碗完毕");

        // 洗碗之后的其他动作,这里就不写了

    }, 2000);
}

// 绑定cook事件
eventEmitter.on("cookEvent", cook);
// 绑定eat事件
eventEmitter.on("eatEvent", eat);
// 绑定wash事件
eventEmitter.on("washEvent", wash);

// 执行cook事件
eventEmitter.emit("cookEvent");

// 开始做饭...
// 做饭完毕
// 开始吃饭...
// 吃饭完毕
// 开始洗碗...
// 洗碗完毕

这种方法的优点是比较容易理解,可以绑定多个事件,每个事件可以指定多个回调函数,而且可以"去耦合"(Decoupling),有利于实现模块化。缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰

3. 发布/订阅

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

和上一个“事件监听”很类似,本人对这种模式理解有限,这里就不列代码误导大家了。

4. Promise

Promise: 由 CommonJS 小组的成员在 Promise/A 规范中提出,目的是为异步编程提供统一接口。

根据 Promise/A 规范,promise 是一个对象,只需要 then 这一个方法。

// 做饭
function cook() {
    console.log("开始做饭...");

    let promise = new Promise(function(resolve, reject) {
        setTimeout(function() {
            console.log("做饭完毕");
    
            resolve();
    
        }, 2000);
    });

    return promise;
}

// 吃饭
function eat(callback) {
    console.log("开始吃饭...");

    let promise = new Promise(function(resolve, reject) {
        setTimeout(function() {
            console.log("吃饭完毕");
    
            resolve();
            
        }, 2000);
    });

    return promise;
}

// 洗碗
function wash() {
    console.log("开始洗碗...");

    let promise = new Promise(function(resolve, reject) {
        setTimeout(function() {
            console.log("洗碗完毕");
    
            // 洗碗之后的其他动作,这里就不写了
            resolve();
    
        }, 2000);
    });

    return promise;
}

cook()
.then(function() {
    return eat();
})
.then(function() {
    return wash();
})
.then(function() {
    console.log("结束...");
})
.catch(function() {
    console.log("好像出什么问题了"); 
});

优点:

回调函数变成了链式写法,程序的流程可以看得很清楚,而且有一整套的配套方法,可以实现许多强大的功能。解决回调地狱(Callback Hell)问题

更好地进行错误捕获

Promise的功能不仅仅只上面用到的,诸如其他all(), race()之类,限于篇幅,大家可以翻看其他文章查看。

结尾

参考文章:Javascript异步编程
参考文章:Promise使用详解

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

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

相关文章

  • ES6-7

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

    mudiyouyou 评论0 收藏0
  • 前端排序算法总结;前端面试题2.0;JavaScript异步编程

    摘要:与异步编程按照维基百科上的解释独立于主控制流之外发生的事件就叫做异步。因为的存在,至少在被标准化的那一刻起,就支持异步编程了。然而异步编程真正发展壮大,的流行功不可没。在握手过程中,端点交换认证和密钥以建立或恢复安全会话。 1、前端 排序算法总结 排序算法可能是你学编程第一个学习的算法,还记得冒泡吗? 当然,排序和查找两类算法是面试的热门选项。如果你是一个会写快排的程序猿,面试官在比较...

    aaron 评论0 收藏0
  • 前端排序算法总结;前端面试题2.0;JavaScript异步编程

    摘要:与异步编程按照维基百科上的解释独立于主控制流之外发生的事件就叫做异步。因为的存在,至少在被标准化的那一刻起,就支持异步编程了。然而异步编程真正发展壮大,的流行功不可没。在握手过程中,端点交换认证和密钥以建立或恢复安全会话。 1、前端 排序算法总结 排序算法可能是你学编程第一个学习的算法,还记得冒泡吗? 当然,排序和查找两类算法是面试的热门选项。如果你是一个会写快排的程序猿,面试官在比较...

    ARGUS 评论0 收藏0
  • 前端排序算法总结;前端面试题2.0;JavaScript异步编程

    摘要:与异步编程按照维基百科上的解释独立于主控制流之外发生的事件就叫做异步。因为的存在,至少在被标准化的那一刻起,就支持异步编程了。然而异步编程真正发展壮大,的流行功不可没。在握手过程中,端点交换认证和密钥以建立或恢复安全会话。 1、前端 排序算法总结 排序算法可能是你学编程第一个学习的算法,还记得冒泡吗? 当然,排序和查找两类算法是面试的热门选项。如果你是一个会写快排的程序猿,面试官在比较...

    April 评论0 收藏0
  • javascript基础总结(二)——异步编程情况

    摘要:异步规定要做一件事,不是立马执行这件事,需要等一定的时间,这样的话,我们不会等着它执行,而是继续执行下面的操作,只有将下面的事情处理完了,才会返回头处理之前的事情如果下面的事情并没有处理完成,不管之前的事情有没有到时间,都踏踏实实的给我等着 异步:规定要做一件事,不是立马执行这件事,需要等一定的时间,这样的话,我们不会等着它执行,而是继续执行下面的操作,只有将下面的事情处理完了,才会返...

    Dionysus_go 评论0 收藏0

发表评论

0条评论

yearsj

|高级讲师

TA的文章

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