04.Eventloop与异步对象

104 阅读3分钟

1. javascript单线程

首先需要明确一点,无论是浏览器中还是nodejs中的javascript,从应用层面上来讲,都是单线程的。

注:Html5中引入了Web Worker来实现多线程,但是无法操作DOM,而且Web Worker完全受主线程控制。

2. Event Loop

浏览器中的Event-loop模型与NodeJs中的模型是不一样的,我们本文主要以浏览器中的javascript为主,NodeJs只做简单说明。

2.1 浏览器中的Event-loop

个人理解Event Loop应该指的是一系列的概念,其中包括执行栈-主线程(Stack),任务队列-(callback queue),还有Event-Loop

上面的这些名词来自于这篇文章:vimeo.com/96425312

1) 简单工作工程 (如下图所示)

  • 浏览器会扫代码中所有的IO操作。
  • 异步操作会交由IO去执行,执行完毕后将IO操作对应的回调函数放到callback queue中。
  • 当主线程中所有的同步任务执行结束后,会检查callback queue中是否有执行结束的回调,如果有就执行。

Event-loop流程示意图

Event-loop内存示意图

2) 可以添加callbackcallback-queue

可以通过setTimeout()方法,将function手动设置到callback-queue中,这样就可以控制某些function的执行顺序。

display(`This is the 1st time to call display()...`);
setTimeout(function() {
    display(`This is the 2nd time to call display()...`);
}, 0);
display(`This is the 3rd time to call display()...`);

/**
 * 输出结果:
 * This is the 1st time to call display()...
 * This is the 3rd time to call display()...
 * This is the 2nd time to call display()...
 * 
 * 因为1st和3rd的调用这两句代码是同步任务放到了主线程执行栈中执行。
 * 2nd这句我们通过调用setTimeout方法放到了callback-queue中,只有主线程中的所有任务执行完成后,才会调用callback-queue中的任务。
*/

2.2 NodeJs中的Event-loop

  • V8引擎解析javascript脚本。
  • 解析后的代码,调用Node API
  • libuv库负责Node API的执行。它将不同的任务分配给不同的线程,形成一个Event Loop,以异步的方式将任务的执行结果返回给V8引擎。
  • V8引擎再将结果返回给用户。

Nodejs Event-loop流程示意图

NodeJs的内容引自阮一峰老师的blog: www.ruanyifeng.com/blog/2014/1…

NodeJs中还引入了process.nextTick()setImmediate()

  • nextTick(): 在当前队列尾部添加回调,也就是说nextTick()设置的回调会在下次队列执行前执行。
  • setImmediate(): 在下一队列头部添加回调,也就是说setImmediate()设置的回调会在下次队列执行时执行。

3. Promise对象

Promise对象是javascript中引入的异步对象,Pomise内部有两个对象:resolve/rejectresolve用来定义异步执行结果成功后的回调函数,reject用来定义异步执行结果失败后的回调。而且,在reactjsvue.js中,非常方便的使用Promise对象支持async - await模式。由于本例中使用babel7的script模式,所以支持async - awaitdemo比较复杂,就不演示了。

// 如何在javascript中使用promise
function simpleExample(text) {
    return new Promise((resolve, reject) => {
        if (text == undefined || text === '')
            reject('error');
            console.log(text);
            resolve('done');
        });
}

var result1 = simpleExample();
var result2 = simpleExample('hello');
result1.then(value => console.log(value)).catch(err => console.log(err)); // error
result2.then(value => console.log(value)).catch(err => console.log(err)); //hello

Promise对象中的执行顺序是如何的呢?

  • Promise中的逻辑将会在Promise对象构造时立即执行
  • Promiseresolve/reject的回调,将会在执行结束后,被放到下一个消息队列的头部
setTimeout(function(){
    console.log(`promise eventloop: ${1}`);
});
    
var promise = new Promise(function(resolve){
    console.log(`promise eventloop: ${2}`);
    resolve();
});
    
promise.then(function(){
    console.log(`promise eventloop: ${3}`);
});
    
console.log(`promise eventloop: ${4}`);

/**
 * promise eventloop: 2  当promise构造时,promise中的逻辑将立即执行
 * promise eventloop: 4  第二步,执行主线程中的任务
 * promise eventloop: 3  promise.resolve中的回调函数,将会被放到callback-queue的顶部执行
 * promise eventloop: 1  setTimeout中的逻辑会放到callback-queue中
*/