javascript的单线程异步机制探究

JavaScript的同步异步模式

JavaScript的语言执行环境都是单线程。单线程就是想排队那样任务需要按顺序一个一个的完成。这种模式的好处是实现起来简单,但是坏处就是如果队列中有一个任务耗费时间很长,那后边的任务就必须等前一个执行完,会拖延整个程序的执行。

为了优化这个问题,JavaScript语言将任务的执行模式分成两种,同步(Synchronous)和异步(Asynchronous)。

同步模式就是后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的。

异步模式则完全不同,每个任务有一个或者多个回调函数,前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务不需要等前一个任务执行完才执行,程序的执行顺序与任务的执行顺序是不一致的。在浏览器端,耗时很长的操作都应该异步执行,避免浏览器失去响应。

那异步模式又有几种实现方式呢,

异步模式有四种实现方式,回调函数方式,事件监听方式,发布-订阅方式和Promise方式

1,回调函数

回调函数就是将函数作为参数传到需要回调的函数内部再执行,例如f1很耗时,f2需要f1的执行结果才能执行,f3不需要f1,f2的结果,需要尽快执行,

那我们就尝试用异步,将f2作为参数传到f1的回调函数内部。代码如下,

function f1(func){

        var tip = '';

        setTimeout(function(){

            for(var i = 0;i <= 10000;i++){

                if(i == 10000){

                    tip = 'f1执行完,f2需要我'

                }

                console.log(i);

            }

            func(tip);

        },0);

    }

    function f2(tip){

        console.log(tip);

    }

    function f3(){

        console.log("f3执行");

    }

    f1(f2);

    f3();

这个异步是实现其实主要是靠setTimeout实现的,这个函数将要执行的函数放到队列最后边也就是f3的后边,所以f3执行完才会执行for循环和f2,js是单线程的,所以异步的实现其实就是将耗时的放到最后边,当任务进程里面的任务执行完之后再去执行后边添加的任务。

2,事件监听

这个思路是采用事件驱动模式。任务的执行不取决于代码的顺序,而是取决于某个事件是否发生。这种模式跟绑定事件的机制其实是一样的,例如给某个DOM元素绑定click事件,当click触发的时候才会执行绑定的函数,那我们现在模拟一个done事件,这里用jQuery的写法。为f1绑定一个done事件,当f1发生done事件,就执行f2。

f1.on('done', f2);

function f1(){

setTimeout(function () {

// f1的任务代码

f1.trigger('done');

}, 0);

}

f1.trigger('done')表示,执行完成后,立即触发done事件,从而开始执行f2。

这种方式与回调函数的区别就是取决于某个事件是否发生来执行异步的,最终实现也是setTimeout实现的。

3,订阅/发布

这个跟事件监听的区别是信号监听,假设有个信号中心,某个任务完成,就像信号中心发个信号,其他任务可以向信号中心订阅这个信号,从而知道自己什么时候可以执行。

Event.subscribe("done", f2);

function f1(){

setTimeout(function () {

// f1的任务代码

Event.publish("done");

}, 1000);

}

f2向信号中心订阅done信号,

Event.publish("done"); 这句意思是当f1执行完,向信号中心发布done,f2接收到信号,开始执行。

4,promise对象是CommonJS工作组提出的一种规范,目的是为异步编程提供统一接口。promise是ECMAScript 6规范内定义的.

Promise是一个对象,它的构造函数接收一个回调函数,这个回调函数参数有两个函数:分别在成功状态下执行和失败状态下执行,Promise有三个状态,分别为:等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected)。

    

var promise = new Promise(function(resolve, reject) {

  if (/* 异步操作成功 */){

    resolve(value);

  } else {

    reject(error);

  }

});

promise.then(function(value) {

  // success

}, function(value) {

  // failure

});

上面代码表示,Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve方法和reject方法。如果异步操作成功,则用resolve方法将Promise对象的状态变为“成功”(即从pending变为resolved);如果异步操作失败,则用reject方法将状态变为“失败”(即从pending变为rejected)。

then()方法是Promise对象的核心,它返回一个新的Promise对象,因此可以像jQuery一样链式操作.

这只是初步对promise的了解,它属于ES6新加的对象,Promise/Deferred异步模型蕴含的编程思想是我们更应该了解的。

参考博客:

JavaScript异步编程原理

JavaScript下的setTimeout(fn,0)意味着什么?

Javascript异步编程的4种方法 

posted @ 2015-05-17 21:57  Jesse-band  阅读(310)  评论(2编辑  收藏  举报