解决异步问题,教你如何写出优雅的promise和async/await,告别callback回调地狱!

简介: 该文章教授了如何使用Promise和async/await来解决异步编程问题,从而避免回调地狱,使代码更加清晰和易于管理。

我们平常在写 js 中,经常只管程序能跑就行,但很少去深究它的原理。更别说还有一个同步和异步的问题了。因此,程序往往有时候出现莫名其妙的卡死或者有时候执行顺序达不到我们想要的结果时自己都不知道往哪里找错。下面的这篇文章中,将讲解同步和异步的问题,以及如何解决异步问题的promise、async/await方法。

在看本文之前,建议大家先对 event loop 有一个了解。了解event loop以及微任务宏任务的相关知识,这样到后面看本文的 async/await 的时候会更友好一些。

下面开始进行本文的讲解。

一、单线程和异步

1、单线程是什么

(1) JS 是单线程语言,只能同时做一件事情

  • 所谓单线程,就是只能同时做一件事情,多一件都不行,这就是单线程。

(2) 浏览器和 nodejs 已支持 JS 启动进程,如 Web Worker

(3) JSDOM 渲染共用同一个线程,因为 JS 可修改 DOM 结构

  • JS 可以修改 DOM 结构,使得它们必须共用同一个线程,这间接算是一件迫不得已的事情。
  • 所以当 DOM 在渲染时 JS 必须停止执行,而 JS 执行过程 DOM 渲染也必须停止。

2、为什么需要异步

当程序遇到网络请求或定时任务等问题时,这个时候会有一个等待时间。

假设一个定时器设置10s,如果放在同步任务里,同步任务会阻塞代码执行,我们会等待10s后才能看到我们想要的结果。1个定时器的等待时间可能还好,如果这个时候是100个定时器呢?我们总不能等待着1000s的时间就为了看到我们想要的结果吧,这几乎不太现实。

那么这个时候就需要异步,通过异步来让程序不阻塞代码执行,灵活执行程序。

3、使用异步的场景

(1)异步的请求,如ajax图片加载

//ajax
console.log('start');
$.get('./data1.json', function (data1) {
   
    console.log(data1);
});
console.log('end');

(2)定时任务,如setTimeout、setInterval

//setTimeout
console.log(100);
setTimeout(fucntion(){
   
    console.log(200);           
}, 1000);
console.log(300);
//setInterval
console.log(100);
setInterval(fucntion(){
   
    console.log(200);           
}, 1000);
console.log(300);

二、promise

早期我们在解决异步问题的时候,基本上都是使用callback回调函数的形式 来调用的。形式如下:

//获取第一份数据
$.get(url1, (data1) => {
   
    console.log(data1);

    //获取第二份数据
    $.get(url2, (data2) => {
   
        console.log(data2);

        //获取第三份数据
        $.get(url3, (data3) => {
   
            console.log(data3);

            //还可以获取更多数据
        });
    });
});

从上述代码中可以看到,早期在调用数据的时候,都是一层套一层, callback 调用 callback ,仿佛深陷调用地狱一样,数据也被调用的非常乱七八糟的。所以,因为 callback 对开发如此不友好,也就有了后来的 promise 产生, promise 的出现解决了 callback hell 的问题。

用一段代码先来了解一下 Promise

function getData(url){
   
    return new Promise((resolve, reject) => {
   
        $.ajax({
   
            url,
            success(data){
   
                resolve(data);
            },
            error(err){
   
                reject(err);
            }
        });
    });
}

const url1 = '/data1.json';
const url2 = '/data2.json';
const url3 = './data3.json';
getData(url1).then(data1 => {
   
    console.log(data1);
    return getData(url2);
}).then(data2 => {
   
    console.log(data2);
    return getData(url3);
}).then(data3 => {
   
    console.log(data3);
}).catch(err => console.error(err));

大家可以看到,运用了 promise 之后,代码不再是一层套一层,而是通过 .then 的方式来对数据进行一个获取,这在写法上就已经美观了不少。那 promise 究竟是什么呢?接下来开始进行讲解。

1、promise的三种状态

  • pending :等待状态,即在过程中,还没有结果。比如正在网络请求,或定时器没有到时间。

  • fulfilled :满足状态,即事件已经解决了,并且成功了;当我们主动回调了 fulfilled 时,就处于该状态,并且会回调 then 函数。

  • rejected :拒绝状态,即事件已经被拒绝了,也就是失败了;当我们主动回调了 reject 时,就处于该状态,并且会回调 catch 函数。

总结:

  • 只会出现pending → fulfilled,或者pending → rejected 状态,即要么成功要么失败;
  • 不管是成功的状态还是失败的状态,结果都不可逆。

2、三种状态的表现和变化

(1)状态的变化

promise 主要有以上三种状态, pendingfulfilledrejected 。当返回一个 pending 状态的 promise 时,不会触发 thencatch 。当返回一个 fulfilled 状态时,会触发 then 回调函数。当返回一个 rejected 状态时,会触发 catch 回调函数。那在这几个状态之间,他们是怎么变化的呢?

1)演示1

先来看一段代码。

const p1 = new Promise((resolved, rejected) => {
   

});

console.log('p1', p1); //pending

在以上的这段代码中,控制台打印结果如下。

状态变化演示1

在这段代码中, p1 函数里面没有内容可以执行,所以一直在等待状态,因此是 pending

2)演示2

const p2 = new Promise((resolved, rejected) => {
   
    setTimeout(() => {
   
        resolved();
    });
});

console.log('p2', p2); //pending 一开始打印时
setTimeout(() => console.log('p2-setTimeout', p2)); //fulfilled

在以上的这段代码中,控制台打印结果如下。

状态变化演示2

在这段代码中, p2 一开始打印的是 pending 状态,因为它没有执行到 setTimeout 里面。等到后续执行 setTimeout 时,才会触发到 resolved 函数,触发后返回一个 fulfilled 状态 promise

3)演示3

const p3 = new Promise((resolved, rejected) => {
   
    setTimeout(() => {
   
        rejected();
    });
});

console.log('p3', p3);
setTimeout(() => console.log('p3-setTimeout', p3)); //rejected

在以上的这段代码中,控制台打印结果如下。

状态变化演示3

在这段代码中, p3 一开始打印的是 pending 状态,因为它没有执行到 setTimeout 里面。等到后续执行 setTimeout 时,同样地,会触发到 rejected 函数,触发后返回一个 rejected 状态的 promise

看完 promise 状态的变化后,相信大家对 promise 的三种状态分别在什么时候触发会有一定的了解。那么我们接下来继续看 promise 状态的表现。

(2)状态的表现

  • pending 状态,不会触发 thencatch
  • fulfilled 状态,会触发后续的 then 回调函数。
  • rejected 状态,会触发后续的 catch 回调函数。

我们来演示一下。

1)演示1

const p1 = Promise.resolve(100); //fulfilled
console.log('p1', p1);
p1.then(data => {
   
    console.log('data', data);
}).catch(err => {
   
    console.error('err', err);
});

在以上的这段代码中,控制台打印结果如下。

状态的表现演示1

在这段代码中, p1 调用 promise 中的 resolved 回调函数,此时执行时, p1 属于 fulfilled 状态, fulfilled 状态下,只会触发 .then 回调函数,不会触发 .catch ,所以最终打印出 data 100

2)演示2

const p2 = Promise.reject('404'); //rejected
console.log('p2', p2);
p2.then(data => {
   
    console.log('data2', data);
}).catch(err => {
   
    console.log('err2', err);
})

在以上的这段代码中,控制台打印结果如下。

状态的表现演示2

在这段代码中, p2 调用 promise 中的 reject 回调函数,此时执行时, p1 属于 reject 状态, reject 状态下,只会触发 .catch 回调函数,不会触发 .then ,所以最终打印出 err2 404

对三种状态有了基础了解之后,我们来深入了解 .then.catch 对状态的影响。

3、then和catch对状态的影响(重要)

  • then 正常返回 fulfilled ,里面有报错则返回 rejected
  • catch 正常返回 fulfilled ,里面有报错则返回 rejected

我们先来看第一条规则: then 正常返回 fulfilled ,里面有报错则返回 rejected

1)演示1

const p1 = Promise.resolve().then(() => {
   
    return 100;
})
console.log('p1', p1); //fulfilled状态,会触发后续的.then回调
p1.then(() => {
   
    console.log('123');
});

在以上的这段代码中,控制台打印结果如下。

then和catch对状态的影响演示1

在这段代码中, p1 调用 promise 中的 resolve 回调函数,此时执行时, p1 正常返回 fulfilled , 不报错,所以最终打印出 123

2)演示2

const p2 = Promise.resolve().then(() => {
   
    throw new Error('then error');
});
console.log('p2', p2); //rejected状态,触发后续.catch回调
p2.then(() => {
   
    console.log('456');
}).catch(err => {
   
    console.error('err404', err);
});

在以上的这段代码中,控制台打印结果如下。

then和catch对状态的影响演示2

在这段代码中, p2 调用 promise 中的 resolve 回调函数,此时执行时, p2 在执行过程中,抛出了一个 Error ,所以,里面有报错则返回 rejected 状态 , 所以最终打印出 err404 Error: then error 的结果。

我们再来看第二条规则catch 正常返回 fulfilled ,里面有报错则返回 rejected

1)演示1(需特别谨慎! !)

const p3 = Promise.reject('my error').catch(err => {
   
    console.error(err);
});
console.log('p3', p3); //fulfilled状态,注意!触发后续.then回调
p3.then(() => {
   
    console.log(100);
});

在以上的这段代码中,控制台打印结果如下。

then和catch对状态的影响演示3

在这段代码中, p3 调用 promise 中的 rejected 回调函数,此时执行时, p3 在执行过程中,正常返回了一个 Error这个点需要特别谨慎!!这看起来似乎有点违背常理,但对于 promise 来说,不管时调用 resolved 还是 rejected ,只要是正常返回而没有抛出异常,都是返回 fulfilled 状态。所以,最终 p3 的状态是 fulfilled 状态,且因为是 fulfilled 状态,之后还可以继续调用 .then 函数。

2)演示2

const p4 = Promise.reject('my error').catch(err => {
   
    throw new Error('catch err');
});
console.log('p4', p4); //rejected状态,触发.catch回调函数
p4.then(() => {
   
    console.log(200);
}).catch(() => {
   
    console.log('some err');
});

在以上的这段代码中,控制台打印结果如下。

then和catch对状态的影响演示4

在这段代码中, p4 依然调用 promise 中的 reject 回调函数,此时执行时, p4 在执行过程中,抛出了一个 Error ,所以,里面有报错则返回 rejected 状态 , 此时 p4 的状态为 rejected ,之后触发后续的 .catch 回调函数。所以最终打印出 some err 的结果。

4、then和catch的链式调用(常考)

学习完以上知识后,我们通过几道题来再总结回顾一下。

第一题:

Promise.resolve().then(() => {
   
    console.log(1);
}).catch(() => {
   
    console.log(2);
}).then(() => {
   
    console.log(3);
});

这道题打印的是 13 ,因为调用的是 promiseresolve 函数,所以后续不会触发 .catch 函数。

第二题:

Promise.resolve().then(() => {
   
    console.log(1);
    throw new Error('error');
}).catch(() => {
   
    console.log(2);
}).then(() => {
   
    console.log(3);
});

这道题打印的是 12 ,虽然调用的是 promiseresolve 函数,但是中间抛出了一个异常,所以此时 promise 变为 rejected 状态,所以后续不会触发 .then 函数。

第三题:

Promise.resolve().then(() => {
   
    console.log(1);
    throw new Error('error');
}).catch(() => {
   
    console.log(2);
}).catch(() => {
     //这里是catch
    console.log(3);
});

这道题打印的是 123 ,跟第二题一样,中间抛出了一个异常,所以此时 promise 变为 rejected 状态,所以后续只触发 .catch 函数。

三、async/await

现代 js 的异步开发,基本上被 asyncawait 给承包和普及了。虽然说 promise 中的 .then.catch 已经很简洁了,但是 async 更简洁,它可以通过写同步代码来执行异步的效果。如此神奇的 asyncawait 究竟是什么呢?让我们一起来一探究竟吧!

1、引例阐述

先用一个例子来展示 promiseasync/await 的区别。假设我们现在要用异步来实现加载图片。

(1) 如果用 promise.then.catch 实现时,代码如下:

function loadImg(src){
   
    const picture = new Promise(
        (resolve, reject) => {
   
            const img = document.createElement('img');
            img.onload = () => {
   
                resolve(img);
            }
            img.onerror = () => {
   
                const err = new Error(`图片加载失败 ${
     src}`);
                reject(err);
            }
            img.src = src;
        }
    )
    return picture;
}

const url1 = 'https://dss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=2144980717,2336175712&fm=58';
const url2 = 'https://dss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=614367910,2483275034&fm=58';

loadImg(url1).then(img1 => {
   
    console.log(img1.width);
    return img1; //普通对象
}).then(img1 => {
   
    console.log(img1.height);
    return loadImg(url2); //promise 实例
}).then(img2 => {
   
    console.log(img2.width);
    return img2;
}).then(img2 => {
   
    console.log(img2.height);
}).catch(ex => console.error(ex));

(2) 如果用 async 实现时,代码如下:

function loadImg(src){
   
    const picture = new Promise(
        (resolve, reject) => {
   
            const img = document.createElement('img');
            img.onload = () => {
   
                resolve(img);
            }
            img.onerror = () => {
   
                const err = new Error(`图片加载失败 ${
     src}`);
                reject(err);
            }
            img.src = src;
        }
    )
    return picture;
}

const url1 = 'https://dss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=2144980717,2336175712&fm=58';
const url2 = 'https://dss2.bdstatic.com/8_V1bjqh_Q23odCf/pacific/1990552278.jpg';


!(async function () {
   
    // img1
    const img1 = await loadImg(url1);
    console.log(img1.width, img1.height);

    // img2
    const img2 = await loadImg(url2);
    console.log(img2.width, img2.height);
})();

大家可以看到,如果用第二种方式的话,代码要优雅许多。且最关键的是,通过 asyncawait ,用同步代码就可以实现异步的功能。接下来我们开始来了解 asyncawait

2、async和await

  • 背景:解决异步回调问题,防止深陷回调地狱 Callback hell
  • PromisePromise then catch 是链式调用,但也是基于回调函数;
  • async/awaitasync/await同步语法,彻底消灭回调函数,是消灭异步回调的终极武器。

3、async/await和promise的关系

(1) async/awaitpromise 并不互斥,两者相辅相成。

(2) 执行 async 函数,返回的是 promise 对象。

(3) await 相当于 promisethen

(4) try…catch 可以捕获异常,代替了 promisecatch

接下来我们来一一(2)(3)(4)演示这几条规则。

第一条规则: 执行 async 函数,返回的是 promise 对象。

async function fn1(){
   
    return 100; //相当于return promise.resolve(100);
}

const res1 = fn1(); //执行async函数,返回的是一个Promise对象
console.log('res1', res1); //promise对象
res1.then(data => {
   
    console.log('data', data); //100
});

在以上的这段代码中,控制台打印结果如下。

async/await第一条规则

大家可以看到,第一个 res1 返回的是一个 promise 对象,且此时 promise 对象的状态是 fulfilled 状态,所以可以调用后续的 .then 并且打印出 data 100

第二条规则: await 相当于 promisethen

!(async function (){
   
    const p1 = Promise.resolve(300);
    const data = await p1; //await 相当于 promise的then
    console.log('data', data); //data 300
})();

!(async function () {
   
    const data1 = await 400; //await Promise.resolve(400)
    console.log('data1', data1); //data1 400
})();

在以上的这段代码中,控制台打印结果如下。

async/await第二条规则

大家可以看到, p1 调用 resolve 回调函数,所以此时 p1 属于 fulfilled 状态,之后 const data = await p1 中的await,相当于 promisethen ,又因为此时 p1 属于 fulfilled 状态,所以可以对 .then 进行调用,于是输出 data 300 。同理在第二段代码中, await 400 时, 400 即表示 Promise.resolved(400) ,因此属于 fulfilled 状态,随后调用 .then ,打印出 data1 400 结果。

再来看一段代码:

!(async function (){
   
    const p2 = Promise.reject('err1');
    const res = await p4; //await 相当于 promise的then
    console.log('res', res); //不打印
})();

在以上的这段代码中,控制台打印结果如下。

async/await第三条规则

大家可以看到, p2 调用 reject 回调函数,所以此时 p2 属于 reject 状态。但因为await是触发 promise 中的 .then ,所以此时 res 不会被触发,于是后续不会对await进行操作,控制台也就不对 console.log('res', res); 进行打印。

第三条规则: try…catch 可以捕获异常,代替了 promisecatch

!(async function () {
   
    const p3 = Promise.reject('err1'); //rejected 状态
    try{
   
        const res = await p3;
        console.log(res);
    }catch(ex){
   
        console.error(ex); //try…catch 相当于 promise的catch
    }
})();

在以上的这段代码中,控制台打印结果如下。

async/await第三条规则

大家可以看到, p3 调用 reject 回调函数,所以此时 p3 属于 rejected 状态,因此它不会执行 try 的内容,而是去执行 catch 的内容, try…catch 中的 catch 就相当于 promise 中的 catch ,且此时 p3 属于 rejected 状态,因此执行 catch ,浏览器捕获到异常,报出错误。

4、异步的本质

从上面的分析中,不管是 promise 还是 async/await ,都是解决异步问题。但是呢,异步的本质还是解决同步的问题,所以,异步的本质是:

  • async/await 是消灭异步回调的终极武器;
  • JS 是单线程的,需要有异步,需要基于 event loop
  • async/await 是一个语法糖,但是这颗糖非常好用!!

我们来看两道 async/await 的顺序问题,回顾 async/await

第一题:

async function async1(){
   
    console.log('async start'); // 2
    await async2();
    //await 的后面,都可以看做是callback里面的内容,即异步。
    //类似event loop
    //Promise.resolve().then(() => console.log('async1 end'))
    console.log('async1 end'); // 5
}

async function async2(){
   
    console.log('async2'); //3
}

console.log('script start');  // 1
async1();
console.log('script end'); // 4

在以上的这段代码中,控制台打印结果如下。

异步的本质1

从上面这段代码中可以看到,先执行同步代码 1 ,之后执行回调函数 async1() ,在回调函数 async1() 当中,先执行同步代码 2 ,之后遇到 await ,值得注意的是, await 的后面,都可以看作是 callback 里面的内容,即异步内容,所以,先执行 await 中对应的 async2() 里面的内容,之后把 await 后面所有的内容放置到异步当中。继续执行 4 ,等到 4 执行完时,整个同步代码已经执行完,最后,再去执行异步的代码,最终输出 5 的内容。

同样的方式来来分析第二题。

第二题:

async function async1(){
   
    console.log('async1 start'); //2
    await async2();

    // 下面三行都是异步回调,callback的内容
    console.log('async1 end'); //5
    await async3();
    // 下面一行是回调的内容,相当于异步回调里面再嵌套一个异步回调。
    console.log('async1 end 2'); //7
}

async function async2(){
   
    console.log('async2'); //3
}

async function async3(){
   
    console.log('async3'); //6
}

console.log('script start'); //1
async1();
console.log('script end'); //4

在以上的这段代码中,控制台打印结果如下。

异步的本质2

这里就不再进行分析啦!大家可以根据第一个案例的步骤进行分析。

5、场景题

最后的最后,我们再来做两道题回顾我们刚刚讲过的 async/await 知识点。

(1)async/await语法

async function fn(){
   
    return 100;
}
(async function(){
   
    const a = fn(); //?? Promise
    const b = await fn(); //?? 100
})();
(async function(){
   
    console.log('start');
    const a = await 100;
    console.log('a', a);
    const b = await Promise.resolve(200);
    console.log('b', b);
    const c = await Promise.reject(300); //出错了,再往后都不会执行了
    console.log('c', c);
    console.log('end');
})(); //执行完毕,打印出哪些内容?
//start
//100
//200

(2)async/await的顺序问题

async function async1(){
   
    console.log('async1 start'); // 2
    await async2();
    //await后面的都作为回调内容 —— 微任务
    console.log('async1 end'); // 6
}

async function async2(){
   
    console.log('async2'); // 3
}

console.log('script start'); // 1

setTimeout(function(){
    //宏任务 —— setTimeout
    console.log('setTimeout'); // 8
}, 0);

//遇到函数,立马去执行函数
async1();

//初始化promise时,传入的函数会立刻被执行
new Promise(function(resolve){
    //promise —— 微任务
    console.log('promise1'); // 4
    resolve();
}).then(function(){
    //微任务
    console.log('promise2'); // 7
});

console.log('script end'); // 5

//同步代码执行完毕(event loop —— call stack 被清空)
//执行微任务
//(尝试触发 DOM 渲染)
// 触发event loop,执行宏任务

这里就不再进行一一解析啦!大家可以前面知识点的学习总计再回顾理解。

四、写在最后

关于 js 的异步问题以及异步的解决方案问题就讲到这里啦!u1s1, promiseasync/await 在我们日常的前端开发中还是蛮重要的,基本上写异步代码时候都会用到 async/await 来解决。啃了16个小时总结了event loop 和 promise 、async/await 问题,希望对大家有帮助。

同时,里面可能有一些讲的不好或者不容易理解的地方也欢迎评论区评论或私信我交流~

关注公众号 星期一研究室 ,不定期分享学习干货~

如果这篇文章对你有用,记得点个赞加个关注哦~

相关文章
|
10天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
6天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2506 14
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
|
6天前
|
机器学习/深度学习 算法 数据可视化
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
2024年中国研究生数学建模竞赛C题聚焦磁性元件磁芯损耗建模。题目背景介绍了电能变换技术的发展与应用,强调磁性元件在功率变换器中的重要性。磁芯损耗受多种因素影响,现有模型难以精确预测。题目要求通过数据分析建立高精度磁芯损耗模型。具体任务包括励磁波形分类、修正斯坦麦茨方程、分析影响因素、构建预测模型及优化设计条件。涉及数据预处理、特征提取、机器学习及优化算法等技术。适合电气、材料、计算机等多个专业学生参与。
1519 14
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
|
8天前
|
编解码 JSON 自然语言处理
通义千问重磅开源Qwen2.5,性能超越Llama
击败Meta,阿里Qwen2.5再登全球开源大模型王座
530 13
|
1月前
|
运维 Cloud Native Devops
一线实战:运维人少,我们从 0 到 1 实践 DevOps 和云原生
上海经证科技有限公司为有效推进软件项目管理和开发工作,选择了阿里云云效作为 DevOps 解决方案。通过云效,实现了从 0 开始,到现在近百个微服务、数百条流水线与应用交付的全面覆盖,有效支撑了敏捷开发流程。
19282 30
|
1月前
|
人工智能 自然语言处理 搜索推荐
阿里云Elasticsearch AI搜索实践
本文介绍了阿里云 Elasticsearch 在AI 搜索方面的技术实践与探索。
18836 20
|
1月前
|
Rust Apache 对象存储
Apache Paimon V0.9最新进展
Apache Paimon V0.9 版本即将发布,此版本带来了多项新特性并解决了关键挑战。Paimon自2022年从Flink社区诞生以来迅速成长,已成为Apache顶级项目,并广泛应用于阿里集团内外的多家企业。
17524 13
Apache Paimon V0.9最新进展
|
8天前
|
人工智能 自动驾驶 机器人
吴泳铭:AI最大的想象力不在手机屏幕,而是改变物理世界
过去22个月,AI发展速度超过任何历史时期,但我们依然还处于AGI变革的早期。生成式AI最大的想象力,绝不是在手机屏幕上做一两个新的超级app,而是接管数字世界,改变物理世界。
457 48
吴泳铭:AI最大的想象力不在手机屏幕,而是改变物理世界
|
1天前
|
云安全 存储 运维
叮咚!您有一份六大必做安全操作清单,请查收
云安全态势管理(CSPM)开启免费试用
353 4
叮咚!您有一份六大必做安全操作清单,请查收
|
2天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。