前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript 同步和异步的执行机制问题

JavaScript 同步和异步的执行机制问题

作者头像
wsuo
发布2020-09-22 10:30:43
7810
发布2020-09-22 10:30:43
举报
文章被收录于专栏:技术进阶之路技术进阶之路

今天做项目的时候遇到了一个问题,当我在请求完后端数据的时候,想去立刻打印出请求出来的信息时,怎么打印都是空的,但是出来这个请求方法之后他又有数值了,于是我很纳闷,研究了1个小时找出了原因。

代码语言:javascript
复制
new Promise((resolve, reject) => {
	wx.request({
	     url: baseUrl + url,
	     data: data || {},
	     method: method || 'GET',
	     success: (result) => {
	         resolve(result);
	     },
	     fail: (err) => {
	         reject(err);
	     },
	     complete: () => {
	         wx.hideLoading();
	     },
	}).then(res => {
		console.log("数据请求成功");
		// 然后设置数据 data
		this.setData({
			data: res.data,
		});
	});
	console.log(data);
	// 这里打印出来为空
})

就像上面的代码一样,打印出来的结果为空,但是出去这个方法,再打印就有了,于是我产生了疑惑,然后查阅资料。

  1. JavaScript 是一门单线程语言。
  2. Event Loop(事件循环)是 JavaScript 的执行机制。

下面我不会直接回答那个问题,而是举别的例子,如果这些例子都搞明白了,那么上面的代码有什么问题相信大家也就都知道了。

大家首先来看一下这段代码:

代码语言:javascript
复制
setTimeout(function(){
    console.log('1.定时器开始')
});
new Promise(function(resolve){
    console.log('2.Promise开始');
    resolve();
}).then(function(){
    console.log('3.执行then函数')
});
console.log('4.代码执行结束');

这段代码的执行结果是:

  • 2.Promise 开始
  • 4.代码执行结束
  • 3.执行 then 函数
  • 1.定时器开始

上面也提到了, JavaScript 是一门单线程的语言,所以我们看到的多线程都是 模拟出来 的,都是纸老虎。

单线程就是使用队列的机制,所有的任务都排着队的执行,在前面排队的任务就先执行,即 先进先出

异步的任务不会先执行,而是先放入一个事件列表,等到主线任务执行完之后再去执行这些事件列表中的数据。

  • 同步和异步任务分别进入不同的执行环境,同步的进入主线程,异步的写入 Event Table 事件列表中。
  • 当事件完成时,把事件列表中的任务推入 Event queue 事件队列,等待执行。
  • 主线程完成所有任务,就去查看事件队列里面,有的话拿出来执行。
  • 上面这个步骤会重复执行,知道没有可执行的任务,形成事件循环(Event Loop)

下面介绍几个异步函数

setTimeout

异步函数,可以延迟执行。

代码语言:javascript
复制
setTimeout(() => {
    console.log('1');
},3000)
console.log('2');

执行结果是:2 、1 。

setInterval

两个定时器兄弟,原理一样,只不过setInterval会每隔指定的时间将注册的函数置入Event Queue。

Promise

Promise 对象是用于异步操作的。

来看一段代码:

代码语言:javascript
复制
$.ajax({
    url:www.javascript.com,
    data:data,
    success:() => {
        console.log('第一个数据返回成功!');
        $.ajax({
            url:www.javascript.com,
            data:data,
            success:() => {
                console.log('第二个数据返回成功!');
                ...如果还有再继续
            }
        })
    }
})

我们可以使用 Promise 对象改造该方法:

代码语言:javascript
复制
function abc(url,param){
    return new Promise(function (resolve, reject) {
        request(url, param, function(){
            resolve('数据请求成功了');
        }, reject);
    });
}
abc.then(function(data){
    console.log(date);//'第一个数据请求成功了';
    return new Promise(function (resolve, reject) {
            request(url, param, function(){
                resolve('数据请求成功了');
            }, reject)
           });
}).then(function(){
    console.log(date);//'第二个数据请求成功了';
});

除了广义的同步任务和异步任务,我们对任务有更精细的定义:

  • 宏任务 包含整个 script 代码块,setTimeout,setInterval
  • 微任务 Promise,process.nextTick
代码语言:javascript
复制
setTimeout(function() {
    console.log('setTimeout');
})
new Promise(function(resolve) {
    console.log('promise');
    resolve();
}).then(function() {
    console.log('then');
})
console.log('console');

执行结果为:promiseconsolethensetTimeout

  • 这段代码作为宏任务,进入主线程。
  • 先看到 setTimeout ,那么注册后把他放到宏任务事件队列 Event Queue
  • 接下来到了 Promise,new Promise 立即执行,then 函数分发到微任务 Event Queue。
  • 遇到 console.log() ,立即执行。
  • 到现在第一次的宏任务执行结束。那么得看看有没有微任务啊,有,then 里面有啊,拿出来执行。
  • 第一轮事件循环结束了,我们开始第二轮循环,当然要从宏任务 Event Queue 开始。我们发现了宏任务 Event Queue 中 setTimeout 对应的回调函数,立即执行。
  • 执行结束。

总结题

代码语言:javascript
复制
console.log('1');

setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})
process.nextTick(function() {
    console.log('6');
})
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})

setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})
附上输出结果:1,7,6,8,2,4,3,5,9,11,10,12
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-09-20 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档