同步与异步

2018-08-08  本文已影响0人  撕心裂肺1232

提到异步,脑子里跳出来的第一个词是ajax异步加载,异步即相互不影响,总感觉异步离我很远,直到去看了相关的文档,瞬间恍然大悟。

1. 单线程

首先了解下,JavaScript是采用的是单线程模型(JavaScript 同时只能执行一个任务,其他任务都必须在后面排队等待)

2. 同步任务和异步任务

程序里面的所有任务,简单分成两类:同步任务(synchronous)和异步任务(asynchronous)。

同步任务

是那些没有被引擎挂起、在主线程上排队执行的任务。只有前一个任务执行完毕,才能执行后一个任务。

异步任务

是那些被引擎放在一边,不进入主线程、而进入任务队列的任务。只有引擎认为某个异步任务可以执行了(比如 Ajax 操作从服务器得到了结果),该任务(采用回调函数的形式)才会进入主线程执行。排在异步任务后面的代码,不用等待异步任务结束会马上运行,也就是说,异步任务不具有”堵塞“效应。
(搬运过来的概念)

口语化,同步就是一个一个地执行,后面的在排队等待。异步就是一个在执行,异步不在等待的队伍中,当达到了触发异步的点,异步被调用执行,异步执行完了继续按照原来的顺序来执行任务。

3. 任务队列和事件循环

首先,主线程会去执行所有的同步任务。等到同步任务全部执行完,就会去看任务队列里面的异步任务。如果满足条件,那么异步任务就重新进入主线程开始执行,这时它就变成同步任务了。等到执行完,下一个异步任务再进入主线程开始执行。一旦任务队列清空,程序就结束执行。

异步任务的写法通常是回调函数。一旦异步任务重新进入主线程,就会执行对应的回调函数。如果一个异步任务没有回调函数,就不会进入任务队列,也就是说,不会重新进入主线程,因为没有用回调函数指定下一步的操作。

(概念有点晕)

4. 异步操作的几种模式

4.1 回调函数
同步:

function f1() {
  // ...
}

function f2() {
  // ...
}

f1();
f2();

异步:

function f1(callback) {
  // ...
  callback();
}

function f2() {
  // ...
}

f1(f2);

4.2 事件监听
异步的执行不取决于代码的顺序,而取决于某个事件(触发它的点)是否发生。

f1.on('done', f2);
function f1() {
  setTimeout(function () {
    // ...
    f1.trigger('done');
  }, 1000);
}

4.3 发布/订阅
可以理解为事件监听的另一种形式。
优势:可以通过查看“消息中心”,了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。

jQuery.subscribe('done', f2);  //订阅
function f1() {                       
  setTimeout(function () {
    // ...
    jQuery.publish('done');     //订阅
  }, 1000);
}
  1. 异步操作的流程控制
    如果有多个异步操作,就存在一个流程控制的问题:如何确定异步操作执行的顺序,以及如何保证遵守这种顺序。
    5.1 串行执行
var items = [ 1, 2, 3, 4, 5, 6 ];
var results = [];

function async(arg, callback) {
  console.log('参数为 ' + arg +' , 1秒后返回结果');
  setTimeout(function () { callback(arg * 2); }, 1000);
}

function final(value) {
  console.log('完成: ', value);
}

function series(item) {
  if(item) {
    async( item, function(result) {
      results.push(result);
      return series(items.shift());
    });
  } else {
    return final(results[results.length - 1]);
  }
}

series(items.shift());

(一开始看了半个钟没get到点)
5.2 并行执行
流程控制函数也可以是并行执行,即所有异步任务同时执行,等到全部完成以后,才执行final函数。

var items = [ 1, 2, 3, 4, 5, 6 ];
var results = [];

function async(arg, callback) {
  console.log('参数为 ' + arg +' , 1秒后返回结果');
  setTimeout(function () { callback(arg * 2); }, 1000);
}

function final(value) {
  console.log('完成: ', value);
}

items.forEach(function(item) {
  async(item, function(result){
    results.push(result);
    if(results.length === items.length) {
      final(results[results.length - 1]);
    }
  })
});

看完才知道,原来我日常写的都是异步!!只是没有一个很清晰的概念,有回调函数的都是异步啦(这样立即应该没错吧)
5.3 并行与串行的结合
所谓并行与串行的结合,就是设置一个门槛,每次最多只能并行执行n个异步任务,这样就避免了过分占用系统资源。
(看到这感觉可以忽略掉后面的代码了)

var items = [ 1, 2, 3, 4, 5, 6 ];
var results = [];
var running = 0;
var limit = 2;

function async(arg, callback) {
  console.log('参数为 ' + arg +' , 1秒后返回结果');
  setTimeout(function () { callback(arg * 2); }, 1000);
}

function final(value) {
  console.log('完成: ', value);
}

function launcher() {
  while(running < limit && items.length > 0) {
    var item = items.shift();
    async(item, function(result) {
      results.push(result);
      running--;
      if(items.length > 0) {
        launcher();
      } else if(running == 0) {
        final(results);
      }
    });
    running++;
  }
}

launcher();

记录此文,方便日后翻阅有关异步的相关知识点,大部分内容来源于网络。
传送门:
https://wangdoc.com/javascript/async/general.html#%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%E7%9A%84%E6%B5%81%E7%A8%8B%E6%8E%A7%E5%88%B6

上一篇下一篇

猜你喜欢

热点阅读