js复习(10)——同步、异步?区别?回调函数?

同步

同步任务就是排队在主线程上执行的任务,只有前一个任务执行完毕,才会执行下一个任务。

console.log('first')
console.log('second')

这里打印的结果是first-second,也就是说同在主线程的任务,会从上到下依次执行,前面代码会阻塞后面的代码执行。

异步

异步任务就是不进入主线程,而是进入到任务队列里面的任务。当主线程所有任务执行完毕之后,任务队列会通知主线程请求执行任务,该任务才会进入主线程执行。

console.log('first')
setTimeout(
   () => { console.log('second');
}, 2000);
console.log('third')

这里最后输出的结果是first-third-second,我们发现定时器里面的任务是最后一个执行的。因为定时器里面的任务被放在了任务队列里面。这里就设计了JS的代码执行规则。
在这里插入图片描述
执行的过程是:

  1. 先执行执行栈中的同步任务。
  2. 当遇到异步任务时,将其放在异步任务处理区中,之后继续执行下面的同步任务。
  3. 当异步任务在异步处理区中被触发,JS会按照触发的先后顺序将其放在任务队列里面等待被调用。
  4. 等到执行栈中的同步任务执行完毕,系统就会按照次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入到执行栈开始执行。
同步和异步的区别

我们都知道同步API可以从返回值中获取到执行结果,但是异步API却不能。

//同步
function sum(a, b){
	return a + b;
}
const result = sum(1, 2)
console.log(result)           //3
异步
function getMsg(){
	setTimeout(function(){
    	return {msg:'Hi'}
    }, 2000)
}
const msg = getMsg()
console.log(msg)      //undefined

为什么是undefined呢?

原因就是当代码执行到定时器的时候,会将异步代码放到任务队列中,之后继续执行同步代码。

在这里定时器被放到任务队列里面,之后继续执行代码也就是调用了getMsg()函数,这个时候getMs()函数里面的异步函数还没有被触发,异步函数并没有阻塞线程,代码继续执行,getMsg()函数默认返回了一个undefined。
那么异步函数怎么获取异步API返回值呢?需要一个新的概念——回调函数

回调函数获取异步API返回值

通过在函数形参中拿到的回调函数引用地址,可以调用回调函数并传递参数给回调函数的形参,这样回调函数就可以获得被调用函数中的信息。

举个例子

function fn(callback){
	callback('Hi')
}
fn(function(n){
	console.log(n)
})

//输出结果是Hi

由此推断,刚刚的代码也可以写成:

function getMsg(callback){
	setTimeout(function(){
		callback({
			msg:'Hi'
		})
	},2000)
}
getMsg(function(data){
	console.log(data)
})
//输出结果是Hi

回调函数解决了异步API不能获取返回值的问题。
接着我们看一个小案例

    console.log('代码开始执行')
    setTimeout(() => {
      console.log('2s后执行的结果')
    }, 2000)
    setTimeout(() => {
      console.log('0s后执行的结果')
    }, 0)
    console.log('代码执行结束')

由于JS的代码执行机制,输出的结果是:代码开始执行--代码执行结束--0s后执行的结果--2s后执行的结果
这显然不是我们需要得到的执行顺序,那么如何解决呢?使用回调函数

    console.log('代码开始执行')
    function getZore(callback) {
      setTimeout(function () {
        callback('123')
      }, 0)
    }
    getZore(function (data) {
      console.log('回调函数被执行')
      console.log(data)
      console.log('回调函数执行结束')
    })
    console.log('代码执行结束')

这里的执行结果是代码开始执行--代码执行结束--回调函数被执行--123--回调函数执行结束
我们发现在回调函数中代码是依次进行的。
回调函数的作用就是,将异步代码写在一个块级作用域中,当其中的异步函数执行完毕后,才调用这个回调函数,这时异步函数已经执行完毕,所以在回调函数中代码就可以如同同步代码一样依次执行。

    console.log('代码开始执行')
    function getZore(callback) {
      setTimeout(function () {
        console.log('2s执行结果')
        setTimeout(function () {
          console.log('0s执行结果')
          callback('123')
        }, 0)
      }, 2000)
    }
    getZore(function (data) {
      console.log(data)
    })
    console.log('代码执行结束')

直接结果是:代码开始执行--代码执行结束--2s执行结果--0s执行结果--123
这样做会有一个后果,就是回调地狱
为了解决回调地狱,ES6里面提供了Promise

Promise

Promise实际上就是在原本的异步API上面包裹一层函数,其中Promise函数的resolve , reject两个参数,实际上和普通的回调函数一样,都接受一个回调函数作为实参,而在运行时返回一个实参给调用他的then或catch两个回调函数,这样就会获得异步API中的执行结果。

let promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        if (true) {
            resolve({name: '张三'})
        }else {
            reject('失败了') 
        } 
    }, 2000);
});
promise.then(result => console.log(result); // {name: '张三'})
       .catch(error => console.log(error); // 失败了)

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值