JS-异步和同步

简单来说同步和异步可以这么形容。
同步:等待结果
异步:不等待结果
需要注意的是异步常常伴随回调一起出现,但是异步不是回调,回调也不一定是异步。
同步的 sleep:

function sleep(seconds){
    var start = new Date()
    while(new Date() - start < seconds * 1000){
          
    }
    return
}
console.log(1)
sleep(3)
console.log('wake up')
console.log(2)
 // 打印顺序是 1, wake up, 2

js在这一段时间内,会一直去查看时间到了没有,时间到了再去执行相应的代码,也就是说js会一直等下去,等待的过程不做任何事情,就是去反复的查看时间到了没有。

异步的 sleep:

function sleep(seconds, fn){
    setTimeout(fn, seconds * 1000)
}
console.log(1)
sleep(3, ()=> console.log('wake up'))
console.log(2)
// 打印顺序是 1, 2, wake up

根据上面的代码可以看出,js在执行代码的时候是不会等待异步代码的结果,而是直接去执行了下面的代码。那么js看到异步代码会做什么昵?其实很简单,就是告诉浏览器,我这有个异步代码,你帮我订个闹钟,时间到了通知我,我去调用一下。这也是为什么js是单线程,可效率很高的原因,因为有很多人帮它做事。

异步的例子:
获取图片的宽度,但是图片加载到页面时需要时间的,因此下面的代码获取到的图片宽度为0:

document.getElementsByTagName('img')[0].width // 宽度为 0
console.log('done')

解决方法:img加载成功后就会触发onload,这样的话就可以在onload后可以获取到width了

document.getElementsByTagName('img')[0].onload = function(){
    console.log(this.width) // 宽度不为 0
    console.log('real done')
}
console.log('done')

AJAX 中的异步
同步:

let request = $.ajax({
  url: '.',
  async: false  // 会一直等待响应
})
console.log(request.responseText)

异步:

$.ajax({
    url: '/',
    async: true, 
    success: function(responseText){ // 执行完会来调用这个函数
        console.log(responseText)
    }
})
console.log('请求发送完毕')  // 请求完,不等响应,就执行本行代码

两种方式可以获取异步的结果

  1. 轮询: 隔一段时间就去查看一下,看有没有结果。
  2. 回调
    回调的形式
    1.Node.js 的 error-first 形式
 fs.readFile('./1.txt', (error, content)=>{
     if(error){
         // 失败
     }else{
         // 成功
     }
 })
  1. jQuery 的 success / error 形式
 $.ajax({
         url:'/xxx',
         success:()=>{},
         error: ()=>{}
     })
  1. jQuery 的 done / fail / always 形式
$.ajax({
        url:'/xxx',
     }).done( ()=>{} ).fail( ()=>{} ).always( ()=> {})
  1. Prosmise 的 then 形式
    $.ajax({
       url:'/xxx',
     }).then( ()=>{}, ()=>{} ).then( ()=>{})

promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。使用回调来获取异步结果,而获取可能成功或者失败,因此不同的人就产生了如上不同的写法,多种写法不够统一,因此就出现了promise规范,promise就是来解决获取结果成功或者失败的命名规范和形式,then(成功函数,失败函数),成功函数和失败函数里面是获取到结果后所做的动作,如 then(成功函数,失败函数)。promise是对函数回调形式的一种规范。
在promise/A+规范中,如链式then里面的第一个then不管是成功函数和失败函数的顺利执行,都会去执行第二个then里面的成功函数,以此类推。但是第一个then里面不管是成功函数和失败函数出现了异常,那么会有第二个then里面的失败函数来接住这个异常。而catch也是捕获异常的方法,通常用来兜底的。相当于then的一个语法糖,也就是第一个(成功)参数传undefined,then(undefined,失败函数)。

自己返回 Promise

function ajax(){
    return new Promise((resolve, reject)=>{
        做事
        如果成功就调用 resolve
        如果失败就调用 reject
    })
}
var promise = ajax()
promise.then(successFn, errorFn)

async / await
把异步代码变成同步代码,也就是用同步的形式写异步代码。await后面跟的是一个会返回promise的函数。一个函数里面有await,那么外面最好写一个async,不然会报错。

实现一个简单的Promise
满足以下需求:

function Promise(???){
    ???
    return ???
}

var promise = new Promise(function(x,y){
    setTimeout(()=>{
        x(101)
    }, 3000)
})
promise.then((z)=>{
    console.log(z)  // 101
})

分析:
首先搞清楚输入和输出是什么!!!涉及到传参为函数的话,要考虑到函数的调用,没有this的话,就把call的第一个参数设为undefined。而Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。通常我们把pending变为fulfilled的过程称为resolved,把pending变为rejected的过程称为rejected。
代码

function Promise(fn){
    var status = 'pending'   // 记录初始状态
    function successNotify(){
        status = 'resolved'
        toDoThen.apply(undefined, arguments)
    }
    function failNotify(){
        status = 'rejected'
        toDoThen.apply(undefined, arguments)
    }
    function toDoThen(){   
        setTimeout(()=>{ // 保证回调是异步执行的
            if(status === 'resolved'){
                for(let i =0; i< successArray.length;i ++)    {
                    successArray[i].apply(undefined, arguments)
                }
            }else if(status === 'rejected'){
                for(let i =0; i< failArray.length;i ++)    {
                    failArray[i].apply(undefined, arguments)
                }
            }
        })

    }
    var successArray = []  // 创建成功队列
    var failArray = []  // 创建失败队列
    fn.call(undefined, successNotify, failNotify)
    return {
        then: function(successFn, failFn){
            successArray.push(successFn) // 把成功函数放进成功队列里面
            failArray.push(failFn) // 把失败函数放进失败队列里面
            return undefined // 简化, 链式then的话可继续返回then
        }
    }
}

你可能感兴趣的:(JS-异步和同步)