javascript异步编程总结

媒介

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('彷佛出什么题目了'); 
});

长处:

  1. 回调函数变成了链式写法,递次的流程能够看得很清晰,而且有一整套的配套要领,能够完成很多壮大的功用。处理回调地狱(Callback Hell)题目
  2. 更好地举行毛病捕捉

Promise的功用不仅仅只上面用到的,诸如其他all(), race()之类,限于篇幅,人人能够翻看其他文章检察。

末端

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

    原文作者:蔡力文
    原文地址: https://segmentfault.com/a/1190000018636603
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞