首页 > 其他分享 >js四种异步方法(回调函数、Promise、Generator、async/await)

js四种异步方法(回调函数、Promise、Generator、async/await)

时间:2022-09-07 15:11:20浏览次数:98  
标签:resolve console log err Generator await js Promise 函数

由于JS运行环境是单线程的,即一次只能完成一个任务,所以多任务时需要排队。异步可以理解为改变执行顺序的操作,异步任务必须在同步任务执行结束之后,从任务队列中依次取出执行。 js常见的异步方法有四种:   1,回调函数callback 函数B作为函数A的入参,且函数A执行了函数B,此时我们把函数A叫做回调函数。(ajax、setTimeout、dom事件回调等都是回调函数) 例如:

function A(callback) {
    console.log("A");
    callback();//函数A执行了函数B
}
function B() {
    console.log("B");
}
A(B);//函数B作为函数A的入参
function A(callback){
    console.log("A");
    callback("param B");//函数A执行了函数"B",给函数"B"入参"param B"
}
A((val) => { //函数"B"作为函数A的入参,"B"有一个入参val
    console.log(val);//输出"param B"
})
  缺点:高耦合,结构混乱,回调函数不能使用 try catch 捕获错误,不能直接 return   2,Promise 当回调的层级较少时,回调函数可以满足我们的需求,但是当层级越来越多,回调越来越多,例如吃饭,要吃饭就要先做饭,要做饭就要先淘米,要淘米就要先买米,要买米就要去菜场(或者APP),去菜场就要坐车,坐车就要准备公交卡……如此形成回调地狱!(下一篇再说回调地狱吧) Promise很好地解决了回调地狱的问题,它包含三种状态:pending、fulfilled(resolved)、rejected。pending是promise的初始状态,resolved表示执行完成且成功的状态,rejected表示执行完成且失败的状态。三个状态不可逆转Promise本身是同步,then的内容是异步:
let p = new Promise((resolve,reject) => {
    console.log("promise本身是同步");
    resolve("then是异步");
}).then((res) => {
    console.log(res);
})
console.log("想不到吧");
输出: then接收两个回调函数,一个表示成功,一个表示失败:
let p = new Promise((resolve,reject) => {
    console.log("promise本身是同步");
    reject("then是异步");
}).then((res) => {
    console.log(res);
},(err) => {
    console.log(err);
})
console.log("想不到吧");
第二个回调也可以使用catch
let p = new Promise((resolve,reject) => {
    console.log("promise本身是同步");
    reject("catch是异步");
}).then((res) => {
    console.log(res);
}).catch((err) => {
    console.log(err);
})
console.log("想不到吧")
promise解决回调地狱的问题的方法是链式调用:
function testP(val) {
    return new Promise((resolve, reject) => {
       resolve(val);
    });
}
testP("0").then(res1 => {
    console.log(res1); //输出0
    return testP("1");
}).then(res2 => {
    console.log(res2); //输出1
    return testP("2");
}).then(res3 => {
    console.log(res3); //输出2
    return testP("3");
}).catch(err => {
    console.log(err);
});
首先testP("0")创建了一个promise,进入pending状态,当resove后进入fulfilled状态第一个then中输出0并返回一个promise,进入pending状态,当resove后进入fulfilled状态,第二个then中输出1并返回一个promise......以此类推。 我们修改函数testP:
function testP(filename){
  return new Promise((resolve,reject) => {
      fs.readFile(filename, (err, data) => {
          if(err) {
              reject(err);
          }else {
              resolve(data);
          }
      }) 
  })
}
testP(url).then(res1 => {
    return testP(url1);
}).then(res2 => {
    return testP(url2);
}).then(res3 => {
    return testP(url3);
}).catch(err => {
    console.log(err);
});
testP返回一个promise,then中传入回调函数,上文我们得出结论promise本身是同步,then是异步,then延迟传入回调函数,此为回调函数延迟绑定。 继续改写testP:
function testP(filename){
  return new Promise((resolve,reject) => {
      fs.readFile(filename, (err, data) => {
          if(err) {
              reject(err);
          }else {
              resolve(data);
          }
      }) 
  })
}
let step1 = testP(url).then(res => {
    return testP(url1);
}).catch((err) => {
    console.log(err);
})
let step2 = step1.then((res) => {
    return testP(url2)
}).catch((err) => {
    console.log(err);
})
let step3 = step2.then((res) => {
    return testP(url3)
}).catch((err) => {
    console.log(err);
})
step3.then((res) => {}).catch((err) => {
    console.log(err);
})
将每一个then拆开,step1/step2/step3都是上文链式调用的内部返回,在step1/step2/step3之后都可以继续完成之后的链式调用,此为返回值穿透。 在step1/step2/step3中都进行了catch捕获异常(即rejected状态),链式调用时,rejected状态的异常信息会一直往后传递,直到被catch接收到,所以不用频繁的catch,此为错误冒泡。 缺点:无法取消 Promise。   3,Generator函数(ES6) Generator 是一个可以暂停执行(分段执行)的函数,函数名前面要加星号,是一个状态机,封装了多个内部状态。
function *myGenerator() {
    yield 'hello';
    yield 'world';
    yield 'wawawa';
    return 'amazing';
}
let mg = myGenerator();
调用myGenerator()但并不会执行,它返回一个指向函数内部的指针对象。调用对象的next()方法使指针指向下一个,每次next()会从上一次暂停的地方继续执行,直到遇到yield或者return,Generator分段执行,yield是标记暂停的地方,next表示恢复执行,每次next返回的是一个对象,包含value和done,value的值是yield表达式后面的值,done表示是否执行完毕。 输出:  缺点:手动迭代。   4,async/await(ES7) 基于Promise实现,使异步代码看起来更像同步代码。 async修饰符加在函数前面,返回一个promise,可以使用then添加回调函数。 await后跟着一个promise或者一个原始类型的值(会自动转成立即 resolved 的 Promise 对象),等待resolve的结果。任何一个await后的Promise发生reject,整个aysnc都会中断,需要try{}catch(err){}来捕获错误。
async function mysw(){
    return 1;
}
mysw();//返回一个promise,其中PromiseResult是1
async function mysw(){
    return new Promise((resolve,reject) => {
        resolve(1)
    });
}
mysw(); //同上
async function mysw(){
    await 1;
}
mysw(); //返回一个promise,其中PromiseResult是undefined
async function mysw(){
    let a = await 1; //1会转成resolve(1)的promise
    console.log(a);
}
mysw(); //输出1,返回PromiseResult是1的promise
async function mysw(){
    let a = await new Promise((resolve) => { //同上
        resolve(1)
    });
    console.log(a);
}
mysw();//同上
async function mysw(){
    let a = await new Promise((resolve) => {
        resolve(1)
    });
    console.log(a)
    return 1;
}
mysw(); //输出1,返回一个PromiseResult值为1的promise
async function mysw(){
    let a = await new Promise((resolve) => {
        resolve("a");
    });
    console.log(a);
    return 1;
}
mysw().then((res) => {
    console.log(res);//输出a,1,返回一个PromiseResult为undefined的promise
});
async function mysw(){
    try {
        let a = await new Promise((resolve) => {
        resolve(x);
    });
        console.log(a);
    } catch(err) {
        console.log(err); 
    }
    return 1;
}
mysw();//ReferenceError: x is not defined

看起来async/await和Generator用法相似,把星号换成async,把yield换成await,它们区别在于:


1,async函数自带执行器

2,语义清楚

3,async函数的返回值是 Promise 对象,Generator 函数的返回值是 Iterator 对象

4,yield命令后面只能是 Thunk 函数或 Promise 对象,而async函数的await命令后面,可以是 Promise 对象和原始类型的值

await语句后面的内容需要等待await的内容执行完才能执行(宏任务除外),可以把await当成是then的语法糖,await之后的内容就相当于then里的回调函数,是异步,根据先微后宏的顺序继续执行(事件循环在后面讲哈)

标签:resolve,console,log,err,Generator,await,js,Promise,函数
From: https://www.cnblogs.com/sxww-zyt/p/16665196.html

相关文章

  • 第 12 题:JS 异步解决方案的发展历程以及优缺点。
    JS异步已经告一段落了,这里来一波小总结1.回调函数(callback)setTimeout(()=>{//callback函数体},1000)缺点:回调地狱,不能用trycatch捕获错误,不能return......
  • js计数排序
    **计数排序**核心思想:找到数组中的最大数和最小数来确定生成数组的大小,根据数组值找到到数组下标与值相同的位置+1,来标识当前值有几个,最后遍历当前数组。letarr=[......
  • 对表白墙js文件的解释
    index.js1Page({23/**4*页面的初始数据5*/6data:{7xcx_appid:"",8},9HuoquDaohangLiebiao(){......
  • common.js模块化规范
    app.js文件://require在代码执行阶段才会调用引入文件,编译(预解析)时不会执行,所以下面会报错//console.log(dep);ReferenceError:depisnotdefinedconstdep=re......
  • async-await
    async函数介绍  1、async函数执行结果是:返回一个Promise对象(newPromise) fn返回普通值(只要不抛错返回的promise的状态就是fulfilled)asyncfunctionf......
  • JS获取屏幕分辨率及当前窗口宽高等数据
    document.body.clientWidth==>BODY对象宽度document.body.clientHeight==>BODY对象高度document.documentElement.clientWidth==>可见区域宽度document.documentElem......
  • 前端JS-Day22
    箭头函数不创建this对象!图片无缝衔接:保证轮播图到最后直接跳转到第一位。 进行轮播图自动播放的时候,可以采取手动调用点击事件的方式操作。window.addEventListene......
  • 第 9 题:Async/Await 如何通过同步的方式实现异步
    首先想要更好的理解Async/Await,需要了解这两个知识点:同步异步背景首先,js是单线程的(重复三遍),所谓单线程,通俗的讲就是,一根筋(比喻有点过分,哈哈)执行代码是一行一行的往......
  • JS版数据结构-链表
    链表代码随笔(JS)/**链表节点*/classNode{el=null;next=null;constructor(el=null,next=null){this.el=el;this.next=next;}}......
  • 第 8 题:setTimeout、Promise、Async/Await 的区别
    1.setTimeoutconsole.log('scriptstart')//1.打印scriptstartsetTimeout(function(){console.log('settimeout')//4.打印settimeout})//2.......