精华内容
下载资源
问答
  •  本文主要是对async / await 的介绍及解决回调地狱方法,关于Promise的详细介绍及Promise解决回调地狱,见:  [ ES6之Promise的介绍及解决回调地狱 ] async / await的介绍: async写在函数的前面,就可以该函数...
  • JS解决回调地狱

    2020-04-19 14:01:27
    解决回调地狱方法 Promise 简化异步操作的回调函数写法 Generator 可以让异步操作停止,达到同步效果 async 是 Generator 函数的语法糖 Promise Promise 对象代表了未来将要发生的事件,用来传递异步操作的消息...

    解决回调地狱的方法

    Promise 简化异步操作的回调函数写法
    Generator 可以让异步操作停止,达到同步效果
    async 是 Generator 函数的语法糖

    Promise

    Promise 对象代表了未来将要发生的事件,用来传递异步操作的消息。
    有三个状态

    • pending: 初始状态,不是成功或失败状态。
    • fulfilled: 意味着操作成功完成。
    • rejected: 意味着操作失败。

    优点:就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise 对象提供统一的接口,使得控制异步操作更加容易。

    Promise:无法取消 Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。第三,当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

    const myPromise = new Promise(function(resolve, reject) {
     // ... 执行异步操作
     if (/* 异步操作成功 */){
      resolve(value);// 调用resolve,代表Promise将返回成功的结果
    } else {
      reject(error);// 调用reject,代表Promise会返回失败结果
    }
    });
    
    

    异步执行完成,做一些事情,我们可以通过 promise的then方法来实现,语法:

    myPromise .then(function(value){
      // 异步执行成功后的回调
          //value的值是上面调用resolve(...)方法传入的值.
    });
    

    如果想要处理promise异步执行失败的事件,还可以跟上catch
    Promise.prototype.then 方法返回的是一个新的 Promise 对象,因此可以采用链式写法。

    myPromise .then(function(value){
      // 异步执行成功后的回调
    }).catch(function(error){
      // 异步执行失败后的回调
    })
    

    Promise.all 方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

    var p = Promise.all([p1,p2,p3]);
    
    • 只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
    • 只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

    Generator

    const fs = require('fs');
    
    const readFile = function (fileName) {
      return new Promise(function (resolve, reject) {
        fs.readFile(fileName, function(error, data) {
          if (error) return reject(error);
          resolve(data);
        });
      });
    };
    
    const gen = function* () {
      const f1 = yield readFile('/etc/fstab');
      const f2 = yield readFile('/etc/shells');
      console.log(f1.toString());
      console.log(f2.toString());
    };
    

    async

    async表示函数里有异步操作,
    await表示让出当前线程,紧跟在后面的表达式需要等待结果。返回值是 Promise

    const asyncReadFile = async function () {
      const f1 = await readFile('/etc/fstab');
      const f2 = await readFile('/etc/shells');
      console.log(f1.toString());
      console.log(f2.toString());
    };
    

    async函数内部return语句返回的值,会成为then方法回调函数的参数。

    执行顺序

    await会跳出整个async函数来执行后面js栈,等本轮事件循环执行完了之后又会跳回到async函数中等待await,等到了结果,然后执行await之后的代码

    展开全文
  • js 解决回调地狱方法

    千次阅读 2019-02-21 15:37:10
    异步编程作为JavaScript中的一部分,具有非常重要的位置,...为了解决回调地狱”,我们可以使用文中所述的这五种常用方法: function拆解 事件发布/订阅模式 Promise Generator async / await 理解各类方法的...

    异步编程作为JavaScript中的一部分,具有非常重要的位置,它帮助我们避免同步代码带来的线程阻塞的同时,也为编码与阅读带来了一定的困难。过多的回调嵌套很容易会让我们陷入“回调地狱”中,使代码变成一团乱麻。为了解决“回调地狱”,我们可以使用文中所述的这五种常用方法:

    • function拆解
    • 事件发布/订阅模式
    • Promise
    • Generator
    • async / await

    理解各类方法的原理与实现方式,了解其中利弊,可以帮助我们更好得进行异步编程


    原文链接:https://www.jianshu.com/p/bc7b8d542dcd

    展开全文
  • 回调地狱 ​ 前端的ajax和jsonp内部充斥着大量的异步,为了能够拿到异步的数据,使用了大量的回调函数,来获取...//开启三个异步的程序,要求能同时拿到所有异步的结果,下边就是用回调地狱方式解决的例子 ajax(...

    回调地狱

    ​ 前端的ajax和jsonp内部充斥着大量的异步,为了能够拿到异步的数据,使用了大量的回调函数,来获取将来异步执行成功之后的数据。如果请求不多时还好,一旦请求的数量达到一定程度,并且复杂度提升以后,会造成一些问题,这就是回调地狱。

    例如:开启三个异步的程序,要求能同时拿到所有异步的结果

    //开启三个异步的程序,要求能同时拿到所有异步的结果,下边就是用回调地狱方式解决的例子
     ajax({
         url:"http://localhost/promise/data/d1.php",
         success:function(res1){
             console.log(res1);
             ajax({
                 url:"http://localhost/promise/data/d2.php",
                 success:function(res2){
                     console.log(res2);
                     ajax({
                       url:"http://localhost/promise/data/d3.php",
                        success:function(res3){
                           console.log(res3);
                           console.log(res1, res2, res3);
                         }
                     })
                 }
             })
         }
     })
    

    回调地狱的缺点:

    • 上边的例子用回调地狱能解决问题,但是有缺点,或者说不优雅。
    • 如果最里面的异步没有执行结束,外面所有的程序是不是都相当于没有结束,有点递归的影子,非常消耗性能。
    • 格式非常不优雅,语义化非常差,不方便调错。

    回调地狱的解决方法

    ​ 在js新版本出现之前,回调地狱自身就是解决方式,新版本出现之后,在新的语法中,提供了一些更优雅的处理方案。

    1.Promise(ES6)解决

    语法:(语言的法律法规,固定!!!!!)
    Promise是一个构造函数
    new的同时立即传参,参数是回调函数,回调函数身上可以接受两个参数,分别是:resolve(success,成功),reject(error,失败)

    var p = new Promise(function(a,b){
    	// 正在执行....
    	// 此处放置异步的程序
    	// a就是在then中的第一个回调函数,表示成功要做的事情
    	// b就是在catch中的第一个回调函数,表示失败要做的事情
    });
    p.then(function(){
    	// 成功的预置函数
    });
    p.catch(function(){
    	// 失败的预置函数
    });
    

    promis和ajax解决上边的例子

     var p1 = new Promise(function(resolve){
         ajax({
             url:"http://localhost/promise/data/d1.php",
             success:function(res1){
                 resolve(res1);
             }
         })
     })
     var p2 = new Promise(function(resolve){
         ajax({
             url:"http://localhost/promise/data/d2.php",
             success:function(res2){
                 resolve(res2);
             }
         })
     })
     var p3 = new Promise(function(resolve){
         ajax({
             url:"http://localhost/promise/data/d3.php",
             success:function(res3){
                 resolve(res3);
             }
         })
     })
    
     p1.then(function(r1){
         console.log(r1);
         return p2;
     }).then(function(r2){
         console.log(r2);
         return p3;
     }).then(function(r3){
         console.log(r3);
     }
    

    promise的封装

    // ajax函数自身执行的时候不再接收成功和失败的处理函数了
    // 交给ajax内部封装的promise处理
    function ajax(ops){
        ops.type = ops.type || "get";
        ops.data = ops.data || {};
        var str = "";
        for(var key in ops.data){
            str += `${key}=${ops.data[key]}&`;
        }
        if(ops.type=="get"){
            let t = new Date().getTime();
            ops.url = ops.url + "?" + str + "__qft="+ t;
        }
        var xhr = new XMLHttpRequest();
        xhr.open(ops.type, ops.url);
        if(ops.type == "get"){
            xhr.send();
        }else{
            xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
            xhr.send(ops.data);
        }
        return new Promise(function(resolve,reject){
            xhr.onreadystatechange = function(){
                if(xhr.readyState === 4 && xhr.status === 200){
                    resolve(xhr.responseText);
                }else if(xhr.readyState === 4 && xhr.status !== 200){
                    reject("当前请求失败了,失败的原因是:" + xhr.status);
                }
            }
        })
    }
    

    当前ajax封装完成之后的调用方式:

    // 当前ajax封装完成之后的调用方式:
     var p1 = ajax({
         type:"get",
         url:"",
         data:{
             user:"admin",
             pass:123
         }
     })
     p1.then(function(res){
         console.log(res)
     })
     p1.catch(function(res){
         console.log(res)
     })
    

    2.async/await(ES7)解决

    在Promise的基础上,再使用async/await(ES7)

    //语法
    async function fn(){
      var res1 = await new Promise(....)
    
      var res2 = await new Promise(....)
    
      var res3 = await new Promise(....)
    
      var res4 = await new Promise(....)
    
      console.log(res1,res2,res3,res4);
     }
    

    async/await解决上边的例子

        async function fn(abc){
            var p1 = await ajax({
                url:"http://localhost/async-await/data/d1.php"
            });
            
            var p2 = await ajax({
                url:"http://localhost/async-await/data/d12312.php"
            });
    
            var p3 = await ajax({
                url:"http://localhost/async-await/data/d3.php"
            });
            
            var p3 = await ajax({
                url:"http://localhost/async-await/data/d3.php"
            });
            
            var p3 = await ajax({
                url:"http://localhost/async-await/data/d3.php"
            });
    
            console.log(p1, p2, p3);
    
            console.log(abc);
        }
    
        document.onclick = function(){
            fn("hello world");
        }
    

    总结

    • promise就是一种固定语法,固定写法,固定传输。
    • 所有的原理都在promise的内部被封装。
    • promise是用来处理所有的异步的回调地狱,不止是ajax,任何一个异步,只是是回调地狱的调用形式,就可以使用promise改造。
    展开全文
  • 那么什么是回调地狱呢?言简意赅的来讲就是我在回调函数里面调用了回调函数又在调用的回调函数的回调函数里面调用了回调函数……就像下图中的代码一样 说是千层饼有点差不多,说是俄罗斯套娃也不为过,就是一个套一...
  • ES6的Promise对象可解决前端开发中常见的回调地狱问题(即大量异步回调函数的嵌套) 为异步编程提供了一种很好的解决方案 首先 什么是异步问题 例: 一个异步的读取文件的方法 const fs=require(fs) const path=...
  • 什么是回调地狱?该如何解决回调地狱

    一、什么是回调地狱呢?

    	地狱这个词不陌生吧!对,没错就是那个十八层地狱的地狱,一层一层的地狱。
    

    1、同步API,异步API的区别

    这个问题呢,需要从Node.js的API说起,这里就会有人问了?博主你不是说回调地狱的问题吗,怎么说到API了,别急,看博主一步一步的解释给你听:

    同步API 是从上到下依次执行,前面的代码会阻塞后面的代码执行
    请看下面这个代码

    
    这里我写了一个for询还1000次,在循环里面打印,在循环体后面是另外的一个打印结果
    结果是什么呢?
    这个需要你自己去敲一下代码才能更好的了解喔!
    
    for(var i=0; i<1000; i++){
    	console.log(i);
    }
    console.log('循环体后面的代码')
    

    异步API不会等待API执行完后在向下执行代码
    看下下面这个代码,会是如何执行呢?

    console.log('代码开始执行')
    //异步操作 setTimout
    setTimout(() =>{ console.log('5秒后执行代码') },5000);//5000就是5秒
    setTimout(() =>{ console.log('0秒后执行代码')},0);
    console.loh('代码结束执行');
    
    这里的执行顺序是:
    代码开始执行
    代码结束执行
    0秒后执行代码
    5秒后执行代码
    
    逻辑梳理:先执行同步的API,在去执行异步的API
          同步API有两个  分别是两个console.log
          异步API也有两个 分别是setTimout
          异步API里面的定时器会先执行0  在执行5
    

    2、Node.js中的异步API

    	使用fs.readFile(‘./demo.txt’,(err,result) =>{});
    	上面这个就是一个异步API
    	是使用系统模块fs去查看文件
    

    如果异步API后面的代码执行依赖当前异步API的执行结果,但实际上后续代码在执行的时候异步API还没有返回结果,这个问题怎么解决呢?

    	fs.readFile(‘./demo.txt’,(err,result) =>{});
    	console.log('文件打印结果')
    

    3、写一个使用异步API,造成的回调地狱案例

    案例需求:依次读取A文件,B文件,C文件

    1. 首先需要创建一个js的文件
    2. 然后分别创建1.txt 2.txt 3.txt
    3. 在每个文本里面写分别写上1 2 3
    4. 这样我们3个文件就创建好了,进入码代码的环节啦
    const fs = require('fs')
    
    fs.readFile('./1.txt','utf8',(err,result1) =>{
        console.log(result1);
        fs.readFile('./2.txt','utf8',(err,result2) =>{
            console.log(result2);
    
            fs.readFile('./3.txt','utf8',(err,result3) =>{
                console.log(result3);
    
            })
        })
    });
    

    执行这个js文件,执行结果是正确的,是不是没毛病!
    但是这我们只写了3个,要是我们写18个呢

    const fs = require('fs')
    
    fs.readFile('./1.txt','utf8',(err,result1) =>{
        console.log(result1);
        fs.readFile('./2.txt','utf8',(err,result2) =>{
            console.log(result2);
    
            fs.readFile('./3.txt','utf8',(err,result3) =>{
                console.log(result3);
                fs.readFile('./3.txt','utf8',(err,result3) =>{
                    console.log(result3);
                    fs.readFile('./3.txt','utf8',(err,result3) =>{
                        console.log(result3);
                        fs.readFile('./3.txt','utf8',(err,result3) =>{
                            console.log(result3);
                            fs.readFile('./3.txt','utf8',(err,result3) =>{
                                console.log(result3);
                                fs.readFile('./3.txt','utf8',(err,result3) =>{
                                    console.log(result3);
                                    fs.readFile('./3.txt','utf8',(err,result3) =>{
                                        console.log(result3);
                                        fs.readFile('./3.txt','utf8',(err,result3) =>{
                                            console.log(result3);
                                            fs.readFile('./3.txt','utf8',(err,result3) =>{
                                                console.log(result3);
                                    
                                            })
                                        })
                                    })
                                })
                            })
                        })
                    })
                })
            })
        })
    });
    

    这样你能理解了吗?这样一层回调嵌套一层回调,是不是有点像地狱的样子!这样的代码也不易去维护。

    二、怎么解决回调地狱呢?

    	Promise的出现就是解决Node.js异步编程中回调地狱的问题
    
    基础语法
    let promise = new Promise((resolve,reject) =>{
    	setTimout(() =>{
    	if(true){
    	//resolve将异步API的执行结果传递出去
    	    resolve({name:"张三"})
    	}else{
    		//reject 也是一个函数,当判断失败的时候,将结果传递出去
      		reject('失败了')
      }	
    },2000);
    })
    //成功了
    promise.then(result => console.log(result));//{name:‘张三’}
    		.catch(error => console.log(error));//失败了
    

    1、使用Promise来完成我们之前做的案例

    1. 创建一个js文件
    2. 文件可以就用之前的文件
    3. 开始代码的编写
    //1、引入系统模块fS
    const fs = require('fs');
    
    //2、创建一个promise对象
    let promise = new Promise((resolve,reject) =>{
    
        fs.readFile('./1.txt','utf8',(err,result) =>{
            if(err !=null){
                reject(err);
            }else{
                resolve(result);
            }
        });
    });
    //文件成功的信息
    promise.then((result) =>{
        console.log(result);
    })
    //文件失败的信息
    .catch((err) =>{
        console.log(err);
    })
    

    2、改进的方法

    const fs = require('fs')
    function p1(){
        return new Promise((resolve,reject) =>{
            fs.readFile('./1.txt','utf8',(err,result) =>{
                resolve(result);
            })
        })
    }
    function p2(){
         return new Promise((resolve,reject) =>{
            fs.readFile('./2.txt','utf8',(err,result) =>{
                resolve(result);
            })
        })
    }
    function p3(){
        return new Promise((resolve,reject) =>{
            fs.readFile('./3.txt','utf8',(err,result) =>{
                resolve(result);
            })
        })
    }
    //依次执行1、2、3
    p1().then((r1) =>{
        console.log(r1);
        //return p2
        return p2();
    })
    .then((r2) =>{
        console.log(r2);
        //return p3()
        return p3();
    })
    .then((r3) =>{
        console.log(r3);
    })
    

    读到这里,你知道什么是回调地狱了吗?并且如何解决它了吗?
    切记!看代码或者看文章的记忆并不深刻哟,要自己去敲代码,这个在面试中也是经常会出现哟!码字不易,希望能一键三连

    2021.3月31日更新

    3、ES7 优化(异步函数)

    异步函数是异步编程语法的终极解决方案,它可以让我们将异步代码写成同步的形式,让代码不再有回调函数嵌套,使代码变得清晰明了

    const fn = async() =>{};
    
    async function fn(){}
    

    之前的案例,优化后的代码如下

    const fs = require('fs');
    const  promisify  = require("util").promisify;
    const readFile = promisify(fs.readFile);
    
    async function run() {
     let  r1 = await readFile('./1.txt','utf8')
      let r2 =  await readFile('./2.txt','utf8')
       let r3 = await readFile('./3.txt','utf8')
        console.log(r1);
        console.log(r2);
        console.log(r3);
    }
    run();
    

    4、总结

    //1.在普通函数定义的前面加上async关键字 普通函数就变成的异步函数
    //2.异步函数默认的返回值是promise对象
    //3.在异步函数内部使用throw关键字进行错误的抛出
    
    //await关键字
    //1.它只能出现在异步函数中
    //2.await promise 它可以暂停异步函数的执行 等待promise对象返回结果后在向下执行
    
    async function p1() {
        return '1';
    }
    async function p2() {
        return '2';
    }
    async function p3() {
        return '3';
    }
    async function run() {
          let r1 = await p1()
          let r2 = await p2()
          let r3 = await p3()
        console.log(r1);
        console.log(r2);
        console.log(r3);
    
    }
    run();
    
    展开全文
  • 回调可以解决:但会出现回调地狱,就像下面一样: 一层一层嵌套,好恶心,哈哈 解决方法2:用jquery的defer函数,能比较好解决 <!DOCTYPE html> <html lang="en"> <head> <meta charset=".
  • 补充一下队列任务优先级:promise.Trick() > promise的回调 > async > setTimeout > setImmediate 不过如果 await 后面跟着 Promise 的话,async1 end 需要等待三个 tick 才能执行到。那么其实这个性能相对来说还是...
  • 目录回调函数:回调地狱:Promise介绍:Promise解决回调地狱: 回调函数:  在一个函数里面以形参的方式调用一个传递进来的函数。 例如: function a(callback){ callback(); } a(function(){ }) 回调地狱:  回...
  • 一文告诉你什么是回调地狱,如何解决回调地狱

    千次阅读 多人点赞 2020-12-13 17:17:40
    二、如何解决回调地狱1.Promise2.async/await总结 前言 在正式了解“回调地狱”之前,我们先了解两个概念: 回调函数 当一个函数作为参数传入另一个参数中,并且它不会立即执行,只有当满足一定条件后该函数才可以...
  • promise解决回调地狱问题

    千次阅读 2018-12-16 21:17:43
    一般来说,我们希望请求数据的代码简洁清晰,具有可读性,所以对重复请求的数据一般可复用是最好的了,故可以封装成一个函数,那么此时会出现一个问题,数据...此时promise可以解决回调地狱得问题,使得代码串联在...
  • 解决回调地狱

    2021-02-20 15:12:39
    //回调地狱 fn(){ this.$axios.get("./json/a.json").then(res=>{ console.log("1",res.data); // this.$axios.get("./json/b.json").then(res=>{ console.log("2",res.data); // this.$a...
  • 解决回调地狱的三个方法 什么是回调地狱? 回调地狱是指在异步js里,回调函数写的太多了,回调套回调,导致代码的可读性下降,十分混乱。 问题需求:1s后输出1,再过1s后输出2,再过1s后输出3。 回调地狱callback ...
  • 回调地狱解决方案

    2020-12-05 15:18:50
    什么是回调地狱 回调地狱就是在回调函数中再嵌套回调函数的一种现象。如图 以上只是演示只写了三层,此次也只是为了讲解回调地狱的解决方案,才做此演示,在正常...它可以解决回调地狱的问题,这也是我们介绍它的原因
  • 解释什么叫回调地狱 以及怎么解决回调地狱 地狱回调概念: 回调函数套回调函数的情况就叫做回调地狱 解决方式: Promise 解决方式 Async/await 解决方式
  • 异步回调地狱是指代码横向增长(比如在Promise对象里面循环嵌套了多个Promise对象)而不是竖向增长,这样的代码就会显得很复杂而且逻辑会变得混乱,可怕的是会写出强耦合的异步代码,后期修改的时候会相当麻烦了。...
  • ES6–promise方法解决回调地狱问题 要解决回调地狱问题,首先要了解回调地狱的产生是由于业务逻辑越来越复杂时,某个函数功能的实现需要依赖另一个函数,也就是把另一个函数作为这个函数的参数使用,当业务逻辑复杂...
  • 什么是回调地狱怎么解决回调地狱的问题 要了解什么是回调地狱,首先要了解什么是同步,什么是异步函数 同步函数:当一个函数是同步执行时,那么当该函数被调用时不会立即返回,直到该函数要做的事情全部做完之后才...
  • 说到回调地狱 想到的是异步 在JavaScript中我们经常会大量使用异步回调,比如使用Ajax请求数据,回调地狱是由于糟糕的编码习惯造成的,功能逻辑代码嵌套的层次太多,导致可读性降低,维护性困难,避免回调地狱的最重要...
  • 3. 解决地狱回调方法有: 3.1 Promise 对象 //导入文件模块 const fs = require("fs"); // function getData(path, datafn, errfn) { // // new Promise()是立即执行构造函数的代码的,构造函数是隐含return的 // ...
  • Promise的用法及如何解决回调地狱

    千次阅读 2019-12-05 17:14:08
    主要谈及: 是什么,...一、setTimeout函数依次执行的传统方法 function fn1(){ setTimeout(()=>{ console.log('fn1') },1000) } function fn2(){ setTimeout(()=>{ console.log('fn2') },1000) } f...
  • JavaScript中避免回调地狱方法

    千次阅读 2018-06-20 10:03:28
    在使用JavaScript时,为了实现某些逻辑经常会写出层层嵌套回调函数,如果嵌套过多,会极大影响代码可读性和逻辑,这种情况也被成为回调...2.1 解决回调嵌套问题(ES6 promise) 2.2 ES6 co/yield方案 2.2.1 什么是G...
  • <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-...
  • JavaScript中的回调地狱解决方法
  • 1、promise是什么 主要用于异步计算 ...稍有不慎就会踏入回调地狱 - 嵌套层次深,不好维护 3、promise简介 promise是一个对象,对象和函数的区别就是对象可以保存状态,函数不可以(闭包除外) 并未剥夺函数
  • 回调地狱 首先 回调地狱 本身不是一个错误,例如 // 等上一个ajax完成,并获取到结果再执行下一个ajax First(function(r1){ Second(r1, function(r2){ ...这时,可以利用 promise 链式调用来解决回调地狱问题,例如:
  • 使用多种方式实现一个类似于sleep的函数,调用await sleep (1000)可以休眠1000毫秒? 可从 Promise、Generator、Async/Await 等角度实现 4种方式: //Promise const sleep = time => { return new Promise...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 11,529
精华内容 4,611
关键字:

解决回调地狱的方法