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
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,423评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,339评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,241评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,503评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,824评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,262评论 1 207
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,615评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,337评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,989评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,300评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,829评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,193评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,753评论 3 230
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,970评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,708评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,295评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,207评论 2 258