Dalam pembelajaran js bahagian hadapan, perkara yang paling tidak selesa untuk semua orang ialah masalah tak segerak Apabila menyelesaikan masalah seperti 异步、回调地狱
, anda mesti belajar janji , janji hanyalah Mimpi ngeri, artikel ini adalah titik masuk dari perspektif yang mudah difahami untuk membantu anda menguasai janji dengan mudah
Jika anda ingin belajar janji, anda mesti faham apa itu pengaturcaraan tak segerak! Seperti yang kita sedia maklum, bahasa js ialah mekanisme 单线程
. Apa yang dipanggil utas tunggal bermaksud melaksanakan mengikut tertib, melaksanakan satu tugas sebelum melaksanakan tugas seterusnya. Walau bagaimanapun, ia tidak menjejaskan kewujudan dua operasi 同步
dan 异步
Kedua-dua operasi ini sebenarnya melakukan perkara pada saluran paip (single thread), tetapi susunan pelaksanaan kedua-dua operasi ini pada satu thread adalah berbeza! Apabila js mencetuskan tugas tak segerak, tugas tak segerak akan diserahkan kepada penyemak imbas untuk diproses Apabila pelaksanaan terhasil, fungsi panggil balik tugas tak segerak akan dimasukkan ke penghujung baris gilir untuk diproses!
Mari kita terangkan tak segerak kami dengan cara yang mudah: 异步就是从主线程发射一个子线程来完成任务
, setiap tugasan mempunyai satu atau lebih fungsi panggil balik (panggilan balik), 前一个任务结束后,不是执行后一个任务,而是执行回调函数
, 后一个任务则是不等前一个任务结束就执行
, jadi susunan pelaksanaan program It tidak konsisten dengan susunan tugasan dan tak segerak.
), dan fungsi ini dipanggil dalam fungsi luaran untuk menyelesaikan tugas tertentu. Ia dipanggil dua cara untuk menulis fungsi panggil balik (Gambar ini diambil daripada bahagian Tutorial Rookie
Dilalui ke fungsi lain (异步编程
, bantu Semua orang lebih memahami apa itu tak segerak! Takrif fungsi panggil balik adalah sangat mudah: fungsi dianggap sebagai
, output
实参
dalam kod ini ialah penggunaan Untuk proses yang panjang, parameter pertamanya ialah外部函数
dan parameter kedua ialah回调函数
Selepas fungsi ini dilaksanakan, utas anak akan dijana selama 1 saat dan kemudian melaksanakan fungsi panggil balik
实现效果相同
setTimeout dalam teks akan menunggu selama 1 saat dalam thread anak, tetapi operasi thread utama tidak akan terjejas! Contohnya, kod berikut:
const text = () => { document.write('hello james') } setTimeout(text,1000)
setTimeout(()=>{ document.write("hello james") },1000)
akan mencetak setTimeout
(回调函数
) dahulu, dan kemudian mengeluarkan 毫秒数
("text"
)hello james
dalam teks satu kedua kemudiannya. anda mesti memahaminya. Apakah
Mari kita lihat konsepnya dahulu:
.setTimeout(()=>{ document.write("hello davis") },1000) console.log('123456');
Sebagai contoh:
Yang pertama dihantar seperti biasa123456
Contohnya, kami menghantar tiga permintaan ajax:主线程
hello davis
子线程
:回调地狱
当一个回调函数嵌套一个回调函数的时候就会出现一个嵌套结构当嵌套的多了就会出现回调地狱的情况
Kod jenis ini kelihatan sangat terseksa! Apabila kami menulis kod seperti ini, kami jatuh ke dalam keadaan Pengalaman kod itu sangat teruk, dan saya keliru selepas membacanya untuk beberapa ketika, kami memperkenalkan kami. gunakan Janji untuk menyelesaikan masalah neraka panggilan balik!
adalah lebih baik daripada penyelesaian tradisional - Fungsi panggilan balik dan Acara - Lebih munasabah dan berkuasa, ia adalah yang bertujuan untuk menulis kompleks
dengan lebih elegan.$.ajax({ url: '我是第一个请求', type: 'get', success (res) { // 现在发送第二个请求 $.ajax({ url: '我是第二个请求', type:'post', data: { a: res.a, b: res.b }, success (res1) { // 进行第三个请求 $.ajax({ url: '我是第三个请求', type:'post', data: { a: res1.a, b: res1.b }, success (res2) { console.log(res2) } }) } }) } })
Keadaan objek tidak dipengaruhi oleh dunia luar. Objek Promise mewakili operasi tak segerak dan mempunyai tiga keadaan:Objek janji mempunyai dua ciri berikut:
可维护性差
Promise
, yang bermaksud ia tidak boleh diubah dengan cara lain.
一旦状态改变,就不会再变,任何时候都可以得到这个结果
。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected
。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。
两个特点摘自于??阮一峰ES6文章
new Promise(function (resolve, reject) { // resolve 表示成功的回调 // reject 表示失败的回调 }).then(function (res) { // 成功的函数 }).catch(function (err) { // 失败的函数 })
出现了new
关键字,就明白了Promise
对象其实就是一个构造函数,是用来生成Promise
实例的。能看出来构造函数接收了一个函数作为参数,该函数就是Promise构造函数的回调函数
,该函数中有两个参数resolve
和reject
,这两个参数也分别是两个函数!
简单的去理解的话resolve
函数的目的是将Promise对象状态变成成功状态
,在异步操作成功时调用,将异步操作的结果,作为参数
传递出去。reject
函数的目的是将Promise对象的状态变成失败状态
,在异步操作失败时调用,并将异步操作报出的错误,作为参数
传递出去。
Promise实例生成以后,可以用then方法
分别指定resolved状态
和rejected状态
的回调函数。
代码示例:
const promise = new Promise((resolve,reject)=>{ //异步代码 setTimeout(()=>{ // resolve(['111','222','333']) reject('error') },2000) }) promise.then((res)=>{ //兑现承诺,这个函数被执行 console.log('success',res); }).catch((err)=>{ //拒绝承诺,这个函数就会被执行 console.log('fail',err); })
代码分析:
上边说到Promise是一个构造函数,new之后等于说调用了构造函数,构造函数中传的参数是一个函数,这个函数内的两个参数分别又是两个函数(
reslove
和reject
),虽然感觉很绕,但是理清思路会很清晰的!我们得到对象
promise
,promise对象中自带有两个方法then
和catch
,这两个方法中会分别再传入一个回调函数,这个回调函数的目的在于返回你所需要成功或失败的信息!那么怎么去调用这两个回调函数呢?
看下方图可以快速理解:
这两个函数分别做为参数(reslove
和reject
)传到上方的函数中去了.随后在构造函数的回调函数中写入异步代码
(例如:ajax
和定时器
),这里使用了定时器作为例子,如果你想表达的是成功回调,你可以在内部调用函数reslove('一般情况下是后端返回的成功数据)
。如果你想表达的是失败回调,你可以调用reject('一般情况下是后端返回的失败信息')
.
这些就是Promise执行的过程!虽然理解着很绕,但是多读几遍绝对有不一样的收获!
then
方法返回的是一个新的Promise实例
(注意:不是原来那个Promise实例
)。因此可以采用链式写法
,即then方法后面再调用另一个then方法
实际案例:
我想要实现在一个数组中查看一个帖子,但是我最终的目的是得到这个帖子下面的所有评论,这该怎么实现呢?
实现思路:
先从一个接口中获取这个帖子的信息,然后通过该帖子的帖子id
从而获取到该帖子下的所有评论
代码如下:
pajax({ url:"http://localhost:3000/news", data : { author : "james" } }).then(res=>{ return pajax({ url : "http://localhost:3000/comments", data : { newsId : res[0].id } }) }).then(res=>{ console.log(res); }).catch(err=>{ console.log(err); })
代码分析:
这里使用了一个Promise已经封装过的ajax,我们从第一个接口中得到了
帖子id
,然后在then中的函数发送第二个请求(携带了第一个请求返回过来的参数
),我们最后想要拿到第二个接口的结果,于是又有了一个then方法,但是在第一个then方法中要把一个新的Promise实例return
出去,这样的话,第二个then才起作用!(这是因为then
方法是Promise 实例
所具有的方法,也就是说,then方法是定义在原型对象Promise.prototype上的
)====>我们可以打印一下:console.log(Promise.prototype)
可以看的出来原型对象Promise.prototype
中是有then方法的!
Promise.all()
Promise.all()
方法用于将多个 Promise 实例,包装成一个新的 Promise 实例
。
语法格式:
const p = Promise.all([p1, p2, p3]);
Promise.all()
方法接受一个数组
作为参数,p1、p2、p3都是 Promise 实例
,如果不是,就会调用Promise.reslove() [该方法可自行了解]
自动将参数转为 Promise 实例,再进一步处理。
说那么多白话没用,我们可以根据一个案例,就可以明白Promise.all()
的用途了。
实际案例:
如果你想实现一个效果:在一个页面中,等到页面中所有的请求返回数据后,再渲染页面,该怎么实现呢?(在实际开发中我们会看到loading
加载页面,等数据返回完后,loading加载页面会消失,整个页面就展现出来了,增强用户的体验。)
实现思路:
通过Promise.all()
方法,等多个接口全部接收到数据后,再统一进行处理,然后渲染页面
代码如下:
console.log("显示加载中") const q1 = pajax({ url:"http://localhost:3000/looplist" }) const q2 = pajax({ url:"http://localhost:3000/datalist" }) Promise.all([q1,q2]).then(res=>{ console.log(res) console.log("隐藏加载中...") }).catch(err=>{ console.log(err) })
代码分析:
在上方代码中,全局打印
显示加载中
是代替loading的页面,表示该页面现在正是loading
页面中,等到q1
和q2
所请求接口都得到返回的信息后,在then
方法中接收收据,并且可以进行渲染页面,同时隐藏了loading
加载页面!
不论是在前端的项目开发中还是在前端的面试过程中,Promise的地位就是举足轻重的
,虽然解决异步编程的终极解决方案是async和await
,但是它们也是基于Promise封装而来的,在以往文章中,我就说过,学习编程重要的是搞懂某个技术是怎么实现的,而不是做一个cv侠
,多去思考,才能进步。继续加油吧,少年!
【相关推荐:javascript视频教程、编程基础视频】
Atas ialah kandungan terperinci Satu artikel akan membantu anda menguasai Promise dengan mudah. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!