【真知拙见】回调地狱和Promise

栏目: JavaScript · 发布时间: 5年前

内容简介:异步编程在JavaScript中非常重要,但是过多的异步编程同时也带来了回调嵌套的问题。以上代码就是一个回调函数。一个函数作为参数需要依赖另一个函数执行调用。但是回调函数有一个致命弱点,容易出现回调地狱(Callback hell)

异步编程在JavaScript中非常重要,但是过多的异步编程同时也带来了回调嵌套的问题。

什么是回调函数?

ajax(url, () => {});复制代码

以上代码就是一个回调函数。一个函数作为参数需要依赖另一个函数执行调用。

但是回调函数有一个致命弱点,容易出现回调地狱(Callback hell)

什么是回调地狱?

let form = document.querySelector('form');
form.onsubmit = function (e) {
  var name = document.querySelector('input').value;
  $.ajax({
    url: "http://demo.com/submit",
    type:'POST',
    data: {name: name},
    success: function(res) {
        if (res.code === 2000) {
            var h1 = document.querySelector('h1').innerHTML;
            h1.innerHTML = res.data.name;
        }
    }
  });
}复制代码

像这样,函数作为参数一层层的嵌套,使得代码块看起来庞大、不清晰,不能一下子分清结构层级,这就称为“回调地狱”。

回调地狱的根本问题与缺点:

  1. 嵌套函数存在耦合性,一旦有所改动,就会牵一发而动全身
  2. 嵌套函数一多,就很难处理错误
  3. 回调函数態使用try...catch...捕获错误,不能直接return

怎么解决回调地狱?

主要原因是因为开发者的编码习惯导致,我们可以通过以下方式来解决:

  • 保持简短的代码风格,尽量使用命名函数,避免使用匿名函数
document.querySelector('form').onsubmit = onFormSubmit();

function onFormSubmit(e) {
  var name = document.querySelector('input').value;
  $.ajax({
    url: "http://demo.com/submit",
    type:'POST',
    data: {name: name},
    success: onSuccess(res)
  });
}

function onSuccess(res){
    if (res.code === 2000) {
        var h1 = document.querySelector('h1').innerHTML;
        h1.innerHTML = res.data.name;
    }
}复制代码
  • 模块化,拆分每一个独立的功能函数,封装、打包成一个单独的js文件,通过import导入
// formHandler.js
module.exports.formSubmit = onFormSubmit;

function onFormSubmit(e) {
  var name = document.querySelector('input').value;
  $.ajax({
    url: "http://demo.com/submit",
    type:'POST',
    data: {name: name},
    success: onSuccess(res)
  });
}

function onSuccess(res){
    if (res.code === 2000) {
        var h1 = document.querySelector('h1').innerHTML;
        h1.innerHTML = res.data.name;
    }
}

// index.js
var formHandler = require('./formHandler');
document.querySelector('form').onsubmit = formHandler.formSubmit;复制代码
  • 处理每一个错误,按照标准规范编码
  • Promise/Gengenerator/Async Function

除了常见的一种回调函数作为异步处理,还有promises,Generators,async是处理异步处理的方式

Promise的特点是什么?

Promise译为承诺,承诺在以后、未来会有一个确切的回复,并且该承诺拥有三种状态:

  1. 等待中(pending)
  2. 完成了(resolved)
  3. 拒绝了(rejected)

这个承诺一旦状态变更了以后,就不能再更改状态了

当我们在构造Promise的时候,构造函数内部的代码是立即执行的

new Promise((resolve, reject) => {
  console.log('new Promise')
  resolve('success')
})
console.log('finish');

// new Promise
// finish复制代码

Promise有什么缺点?

无法取消Promise,错误需要通过回调函数来捕获

什么是Promise链?Promise构造函数执行和then函数执行有什么区别?

Promise

实现了链式调用,也就是说每次调用 then 之后返回的都是一个 Promise ,并且是一个全新的 Promise ,原因也是因为状态不可变。如果你在 then 中使用了return ,那么 return 的值会被 Promise.reslove()

包装

Promise.resovle(1)
    .then(res => {
        console.log(res); // 1
        return 2; // 包装成了 Promise.reslove(2)
    })
    .then(res => {
        console.log(res); // 2
    })
复制代码

Promise也解决了地狱回调的问题:

// old
ajax(url, () => {
    // 处理逻辑
    ajax(url1, () => {
        // 处理逻辑
        ajax(url2, () => {
            // 处理逻辑
        })
    })
})

// new
ajax(url)
    .then(res => {
        console.log(res);
        return ajax(url1);
    })
    .then(res => {
        console.log(res);
        return ajax(url2);
    })
    .then(res => console.log(res));
复制代码

async和await

await 的同步只是在 async 函数里同步,但并不会阻塞其他外部代码的执行。而这也是 await 必须放在 async 函数里的原因

async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。


以上所述就是小编给大家介绍的《【真知拙见】回调地狱和Promise》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

C++ Primer Plus

C++ Primer Plus

Stephen Prata / 张海龙、袁国忠 / 人民邮电出版社 / 2012-6-19 / 99.00元

C++是在C语言基础上开发的一种集面向对象编程、通用编程和传统的过程化编程于一体的编程语言,是C语言的超集。本书是根据2003年的ISO/ANSI C++标准编写的。通过大量短小精悍的程序详细而全面地阐述了C++的基本概念和技术。全书分为18章和10个附录,分别介绍了C++程序的运行方式、基本数据类型、复合数据类型、循环和关系表达式、分支语句和逻辑操作符、函数重载和函数模板、内存模型和名称空间、类......一起来看看 《C++ Primer Plus》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具