HTML 之 JS异步 promise async await

所谓回调函数,就是把任务的第二段单独写在一个函数里面,等到重新执行这个任务的时候,就直接调用这个函数。

为什么 Node.js 约定,回调函数的第一个参数,必须是错误对象err(如果没有错误,该参数就是 null)?原因是执行分成两段,在这两段之间抛出的错误,程序无法捕捉,只能当作参数,传入第二段。

fs.readFile('/etc/passwd', function (err, data) {
  if (err) throw err;
  console.log(data);
});

回调函数本身并没有问题,它的问题出现在多个回调函数嵌套。难想象,如果依次读取多个文件,就会出现多重嵌套。代码不是纵向发展,而是横向发展,很快就会乱成一团,无法管理。回调地狱其实就是这个:

doSomethingAsync1(function(){
 4     doSomethingAsync2(function(){
 5         doSomethingAsync3(function(){
 6             doSomethingAsync4(function(){
 7                 doSomethingAsync5(function(){

一旦嵌套层数加深,就会出现“回调金字塔”的问题,就像example 4那样,如果这里面的每个回调函数中又包含了很多业务逻辑的话,整个代码块就会变得非常复杂。从逻辑正确性的角度来说,上面这几种回调函数的写法没有任何问题,但是随着业务逻辑的增加和趋于复杂,这种写法的缺点马上就会暴露出来,想要维护它们实在是太痛苦了,这就是“回调地狱(callback hell)”。

异步代码回调函数中的异常无法被外层的try/catch语句捕获。

Promise就是为了解决这个问题而提出的。它不是新的语法功能,而是一种新的写法,允许将回调函数的横向加载,改成纵向加载。采用Promise,连续读取多个文件,它会立即返回,但是返回的东西必须调用.then才会有最终结果。

var readFile = require('fs-readfile-promise');

readFile(fileA)
.then(function(data){
  console.log(data.toString());
})
.then(function(){
  return readFile(fileB);
})
.then(function(data){
  console.log(data.toString());
})
.catch(function(err) {
  console.log(err);
});
function read(filename){ 
    // 相当于把异步函数包裹在Promise中
    var promise = new Promise(function(resolve, reject){
        fs.readFile(filename, 'utf8', function(err, data){
            if (err){
                reject(err);
            }
            resolve(data);
         })
    });
    return promise;
}

这里的两个function分别就是resolve和reject,非常直观,很不错。怎么说呢?这段代码不能按照常理思考,这个new Promise操作是会执行到里面的,同时return。。。异步执行的,resove和reject就相当于异步的return了,就是如此。用的时候就then,对吧。

Promise 的最大问题是代码冗余,原来的任务被Promise 包装了一下,不管什么操作,一眼看去都是一堆 then,原来的语义变得很不清楚。

gengator的yelid就是return,只不过它是中间阶段的return。

{
  function* gen() {
    yield 'hello'
    yield 'world'
    return 'ending'
  }

  let it = gen()

  it.next()   // {value: "hello", done: false}
  it.next()   // {value: "world", done: false}
  it.next()   // {value: "ending", done: true}
  it.next()   // {value: undefined, done: true}

只不过返回的也不是输出什么,而是包装输出,但还是输出。

一个函数只能执行一次 return 语句,而在 Generator 函数中可以有任意多个 yield

如果在 Generator 函数里面调用另一个 Generator 函数,默认情况下是没有效果的

由于 Generator函数是 “惰性求值”,执行到第一个 yield 时才会计算求和,并加计算结果返回给遍历器对象 {value: 14, done: false}

也就是说,把异步这个定义转化为了中断!

不是说取代异步,而是说管理异步。async是属于es7的。转码器 Babel 和 regenerator 都已经支持,转码后就能使用。

只有一个await是没有必要的,因为迭代这么多只是管理多个异步而已,单纯一个异步是不需要什么解决方案的。

promise是单个异步解决方案,对呀,要说异步,直接传一个函数就行了呀。

传参异步->promise->async

无论有没有await,async返回的永远都是promise,如果在函数中 return 一个直接量,async 会把这个直接量通过 Promise.resolve() 封装成 Promise 对象。

Promise.resolve(x) 可以看作是 new Promise(resolve => resolve(x)) 的简写,可以用于快速封装字面量对象或其他对象,将其封装成 Promise 实例。

现在回过头来想下,如果 async 函数没有返回值,又该如何?很容易想到,它会返回 Promise.resolve(undefined)

反正最后都有then,有什么意义呢?举个例子,例如依次进行增删查改4个异步操作。它会更方便么?

async zscg(){
  await zeng();
  await shan();
  await cha();
  await gai();
}

注意这几个await是依次执行的,如果返回什么东西,就在前面输出好了,简直太棒了,根本不用输出什么,因为有什么操作就直接在里面实现了!如果真要返回一个东西,那也是个promise,调用.then就好了!

其实promise并不是一无是处,它最重要的就是包装另一个promise,返回加工过的结果!现在老是用async,都不会用promise了。

 

执行的大意:

    同步环境执行(step1) -> 事件循环1(step4) -> 事件循环2(step4的重复)…

也就是说,异步函数需要等到所有同步代码执行完毕后才会执行。如果乱给函数加异步,就很有可能导致加载过程颠倒混乱,就是如此。

Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。

Promse.all在处理多个异步处理时非常有用,比如说一个页面上需要等两个或多个ajax的数据回来以后才正常显示,在此之前只显示loading图标。

需要特别注意的是,Promise.all获得的成功结果的数组里面的数据顺序和Promise.all接收到的数组顺序是一致的,即p1的结果在前,即便p1的结果获取的比p2要晚。这带来了一个绝大的好处:在前端开发请求数据的过程中,偶尔会遇到发送多个请求并根据请求顺序获取和使用数据的场景,使用Promise.all毫无疑问可以解决这个问题。

Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。
原理是挺简单的,但是在实际运用中还没有想到什么的使用场景会使用到。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaScript中,异步请求通常使用async和await关键字来处理。async函数相当于生成器的语法糖,而await关键字用于暂停代码的执行,以等待异步操作的完成。以下是使用async和await处理异步请求的几种常见方式: 1. 单个异步请求:使用Promise。 例如:`async function fetchData() { const response = await fetch('url'); const data = await response.json(); return data; }` 2. 多个并行的异步请求:使用Promise.all或Promise.race。 例如:`async function fetchMultipleData() { const promises = [fetch('url1'), fetch('url2'), fetch('url3')]; const responses = await Promise.all(promises); const data = responses.map(response => response.json()); return data; }` 3. 多个串行的异步请求:使用async和await的链式操作。 例如: ``` async function fetchSequentialData() { const response1 = await fetch('url1'); const data1 = await response1.json(); const response2 = await fetch('url2'); const data2 = await response2.json(); return [data1, data2]; } ``` 总结来说,使用async和await可以简化异步请求的处理,使代码看起来更加同步和易于理解。您可以根据具体的需求选择合适的方式来处理异步请求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [深入浅出JS—21 异步代码处理方案之async-await](https://blog.csdn.net/qq_36154157/article/details/124838720)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [JS异步编程(async、await详解)](https://blog.csdn.net/weixin_46240162/article/details/113531714)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值