JavaScript 异步编程:从回调到探索 Promise的秘密

一、引言

JavaScript 是单线程语言,一次默认只能做一件事。但我们在开发中经常遇到网络请求、定时器、文件读取等耗时操作------如果傻等它们完成,页面就会卡死。为了解决这个问题,JavaScript 引入了异步机制。本文将首先梳理同步与异步的区别、什么是线程与进程、回调函数的用法与产生原因、回调地狱,以及本文的重点:如何利用 Promise 优雅地解决这些问题。

二、同步与异步

  • 同步执行------能按照我们写的代码顺序从上往下依次执行,执行完前边的再执行后边的
  • 异步执行------在执行过程中,如果碰到一个耗时的任务,就分精力出来同时执行另一个任务,以高效率执行完整个代码

三、线程与进程

  • 线程:CPU执行指令所需要的时间
  • 进程:CPU接收到一个指令,到加载完上下文所需要的时间

四、首代方法------回调

启用V8来运行js这可以称之为一个进程,但是V8引擎默认只会开启一个线程来执行代码,所以遇到耗时的任务,V8会先将它挂起,先去执行不耗时的任务,这样就出现了一个严重的问题:

当不耗时的B函数依赖于耗时的A函数的执行结果时,V8会先执行不耗时的函数B

举个例子:

js 复制代码
let a = null
function A() {
  setTimeout(() => {
    a = 100
  }, 1000)
}
function B() {
  console.log(a);
}

A()          //函数A是个耗时函数,函数B是不耗时的,V8就会先把A挂起去执行B,
B()          //但是B此时找不到值,因为a的赋值语句还未执行。

于是你便会想,把函数B的调用写在函数A的a=100后面,这样,我们就可以正常输出100了,这便是函数回调。

但是当程序繁重时,排查问题的难度大,可读性差,这就造成了所谓的回调地狱

五、最终的promise解决

那么为了解决回调地狱的问题,我们便引入promise函数。 一个 Promise 实例代表一个未来才会完成(或失败)的异步任务。它有三种状态:

  • pending(进行中):初始状态,既不是成功也不是失败。
  • fulfilled(已成功):操作成功完成。
  • rejected(已失败):操作失败。

让我们从具体案例中来应用学习:

js 复制代码
function date() {
    setTimeout(() => {
        console.log('约会成功');
    }, 2000);
}

function marry() {
    setTimeout(() => {
        console.log('结婚成功');
    }, 1000);
}

date()       //这样有前文可知运行结果是:       结婚成功
marry()      //                              约会成功

那么我们会想:如果marry()的执行条件是date()执行完成,很显然就可解决此烦恼

那如果我们要这样做,我们就可以利用promise函数自带的状态属性:

date成功------>状态更改为成功------>执行marry

我们便可以这样写代码:

js 复制代码
function date() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            console.log('约会成功');
            resolve('yes')     
        }, 2000);
    })
}

function marry() {
    return new Promise((res) => {
        setTimeout(() => {
            console.log('结婚成功');
            res()
        }, 1000);
    })
}

date().then(() => {
        return marry()
    })
  • return new Promise(...)

    date() 被调用时,会立即返回一个 Promise 对象,初始状态为 pending

  • 函数 (resolve, reject) => { ... }

    这个函数会同步立即执行(Promise 构造函数内部会马上调用它)。

  • 回调函数内部:

    • resolve('yes')将 Promise 状态从 pending 改为 fulfilled ,并且把字符串 'yes' 作为成功结果传递出去。
  • date()执行完毕后此时.then检测到状态被改变,执行marry()

六、总结

JavaScript 借助事件循环和任务队列,在单线程基础上实现了非阻塞的异步编程;而 Promise的出现,让异步代码的书写与维护越来越优雅。

相关推荐
7yue1 小时前
我用 AI 把 Learn Claude Code 改写成了 TypeScript + 代数效应版本
前端
daols881 小时前
vxe-table 进阶:同时使用 formatter 与 cell-render 实现格式化与样式定制
前端·javascript·vue.js·vxe-table
用户059540174461 小时前
用LangChain+FastAPI构建私有知识库踩坑实录:这3个问题让我排查了整整8小时
前端·css
Momo__1 小时前
CSS View Transitions 新语法:sibling-index() + ident(),千级元素命名难题的终局方案
前端·css
前端张三1 小时前
ant design vue table 使用虚拟滚动
前端·javascript·vue.js
木子雨廷1 小时前
Flutter 内存管理实战:从 GC 原理到 DevTools 泄漏排查
前端·flutter
Rkgua1 小时前
TS中`Function`、`CallableFunction` 和 `NewableFunction`的函数区别
前端
Asize1 小时前
重生之我在 Vibe Coding 时代当程序员:第十一课,JS底层 :变量提升真相
前端·javascript
HYCS1 小时前
用pixi.js实现fabric.js(五):事件系统
前端·javascript·canvas