В этой статье будут обобщены распространенные сценарии применения Promise при разработке нашего проекта на основе нашего собственного использования Promise ES6.Конечно, Promise может быть не единственным вариантом, но как квалифицированный разработчик интерфейса мы должны это понимать.
Promise.all
Синтаксис: Promise.all(итерируемый)
Параметры: повторяемый объект, например Array.
возвращаемое значение:
-
Если переданный итерируемый объект пуст, это разрешенный промис.
Promise.all([]).then(res=>{ console.log(res)//[] })
-
Асинхронно разрешенное обещание (если переданный объект Iterable не содержит обещание). Обратите внимание, что в этом случае Google Chrome 58 возвращает выполненное обещание.
Promise.all([1,2,3]).then(res=>{ console.log(res)//[1,2,3] })
-
Это возвращенное обещание будет разрешено/отклонено асинхронно (когда стек пуст), когда все обещания в данном итерируемом объекте будут разрешены или когда любое из обещаний отклонено.
- когда все промисы в данной итерации разрешены
let promise1 = new Promise((resolve,reject)=>{ resolve(1) }) let promise2 = new Promise((resolve,reject)=>{ resolve(2) }) Promise.all([promise1,promise2,3]).then(res=>{ console.log(res)//[1,2,3] })
- когда любое обещание в данной итерации отклоняется
let promise1 = new Promise((resolve,reject)=>{ resolve(1) }) let promise2 = new Promise((resolve,reject)=>{ reject(2) }) Promise.all([promise1,promise2,3]).then(res=>{ console.log(res) }).catch(err=>{ console.log(err)//2 })
описывать:
Этот метод полезен для агрегирования результатов нескольких промисов, В ES6 несколько асинхронных запросов Promise.all могут выполняться параллельно:
1. Когда все результаты возвращены успешно, вернуть успех в порядке запросов;
2. При наличии метода отказа введите метод отказа;
Сценарий 1. Несколько результатов запроса объединяются.
Конкретное описание: страница имеет несколько запросов. Нам нужно, чтобы все запросы возвращали данные перед обработкой и рендерингом вместе.
Мысль: если есть одновременные запросы, статус загрузки каждого запроса должен быть установлен отдельно. Если есть несколько запросов, несколько загрузок могут перекрываться. Контент, отображаемый на странице, зависит от скорости данных, возвращаемых запросом, который Конкретно это отражается в процессе рендеринга.Для опыта мы можем использовать все запросы для возврата данных, а затем рендерить их вместе.В это время мы отключаем индивидуальные настройки загрузки для запросов, и агрегируем результаты запросов через Promise.all. От начала и до конца мы устанавливаем только одну загрузку.
//1.获取轮播数据列表 function getBannerList(){ return new Promise((resolve,reject)=>{ setTimeout(function(){ resolve('轮播数据') },300) }) } //2.获取店铺列表 function getStoreList(){ return new Promise((resolve,reject)=>{ setTimeout(function(){ resolve('店铺数据') },500) }) } //3.获取分类列表 function getCategoryList(){ return new Promise((resolve,reject)=>{ setTimeout(function(){ resolve('分类数据') },700) }) } function initLoad(){ // loading.show() //加载loading Promise.all([getBannerList(),getStoreList(),getCategoryList()]).then(res=>{ console.log(res) // loading.hide() //关闭loading }).catch(err=>{ console.log(err) // loading.hide()//关闭loading }) } //数据初始化 initLoad()
Сценарий 2: объединение результатов запроса на слияние и обработка ошибок
Описание: нам нужно обрабатывать логику рендеринга данных и обработки ошибок запроса отдельно, если запросов несколько, нам нужно писать в нескольких местах
Мышление: Можем ли мы объединить несколько запросов вместе, даже если некоторые запросы не пройдут, они нам вернутся, нам нужно только обработать данные и неправильную логику в одном месте.
//1.获取轮播图数据列表 function getBannerList(){ return new Promise((resolve,reject)=>{ setTimeout(function(){ // resolve('轮播图数据') reject('获取轮播图数据失败啦') },300) }) } //2.获取店铺列表 function getStoreList(){ return new Promise((resolve,reject)=>{ setTimeout(function(){ resolve('店铺数据') },500) }) } //3.获取分类列表 function getCategoryList(){ return new Promise((resolve,reject)=>{ setTimeout(function(){ resolve('分类数据') },700) }) } function initLoad(){ // loading.show() Promise.all([ getBannerList().catch(err=>err), getStoreList().catch(err=>err), getCategoryList().catch(err=>err) ]).then(res=>{ console.log(res) // ["获取轮播图数据失败啦", "店铺数据", "分类数据"] if(res[0] == '轮播图数据'){ //渲染 }else{ //获取 轮播图数据 失败的逻辑 } if(res[1] == '店铺数据'){ //渲染 }else{ //获取 店铺列表数据 失败的逻辑 } if(res[2] == '分类数据'){ //渲染 }else{ //获取 分类列表数据 失败的逻辑 } // loading.hide() }) } initLoad()
Иногда страница зависает, это может быть вызвано исключением интерфейса или просто неактуальным интерфейсом. Так почему же сбой интерфейса приводит к тому, что на всей странице нет данных? Promise.all сообщает нам, что если одно из обещаний в параметре не выполняется (отклонено) и обратный вызов этого экземпляра не выполняется (отклоняется), то обратный вызов метода не будет выполнен.Приведенный выше вариант использования может просто решить эту проблему.
Сценарий приложения 3. Проверка соответствия нескольких результатов запроса условиям
Описание: В проекте апплета WeChat для проверки безопасности входного содержимого формы вызывается метод, написанный облачной функцией.В форме есть 7 полей, которые необходимо проверить, все из которых называются интерфейс проверки безопасности контента, все проверки. Если они пройдены, можно выполнить обычную отправку
function verify1(content){ return new Promise((resolve,reject)=>{ setTimeout(function(){ resolve(true) },200) }) } function verify2(content){ return new Promise((resolve,reject)=>{ setTimeout(function(){ resolve(true) },700) }) } function verify3(content){ return new Promise((resolve,reject)=>{ setTimeout(function(){ resolve(true) },300) }) } Promise.all([verify1('校验字段1的内容'),verify2('校验字段2的内容'),verify3('校验字段3的内容')]).then(result=>{ console.log(result)//[true, true, true] let verifyResult = result.every(item=>item) //验证结果 console.log(verifyResult?'通过验证':'未通过验证')// 通过验证 }).catch(err=>{ console.log(err) })
Promise.race
Синтаксис: Promise.race(итерируемый)
параметр:iterable Итерируемые объекты, такие как Array. Итерируемый.
возвращаемое значение:Метод Promise.race(iterable) возвращает обещание, которое разрешается или отклоняется после разрешения или отклонения обещания в итераторе.
описыватьФункция гонки возвращает обещание, которое будет выполнено так же, как выполнено первое переданное обещание. Он может либо разрешить, либо отклонить, в зависимости от того, какое из двух действий будет выполнено первым.
Если пройденная итерация пуста, возвращенное обещание будет ждать вечно.
Если итерация содержит одно или несколько значений, не являющихся промисами, и/или разрешенные/отклоненные промисы, Promise.race будет разрешаться в первое значение, найденное в итерации.
Сценарий приложения 1: тайм-аут запроса изображения
//请求某个图片资源 function requestImg(){ var p = new Promise(function(resolve, reject){ var img = new Image(); img.onload = function(){ resolve(img); } //img.src = "https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-assets/v3/static/img/logo.a7995ad.svg~tplv-t2oaga2asx-image.image"; 正确的 img.src = "https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-assets/v3/static/img/logo.a7995ad.svg1~tplv-t2oaga2asx-image.image"; }); return p; } //延时函数,用于给请求计时 function timeout(){ var p = new Promise(function(resolve, reject){ setTimeout(function(){ reject('图片请求超时'); }, 5000); }); return p; } Promise .race([requestImg(), timeout()]) .then(function(results){ console.log(results); }) .catch(function(reason){ console.log(reason); });
Сценарий приложения 2: Запрос тайм-аута запроса
Описание: Иногда мы одну секунду читаем новости, а в следующую секунду после входа в лифт мобильная страница выдает сообщение "плохая сеть"
//请求 function request(){ return new Promise(function(resolve, reject){ setTimeout(()=>{ resolve('请求成功') },4000) }) } //请求超时提醒 function timeout(){ var p = new Promise(function(resolve, reject){ setTimeout(function(){ reject('网络不佳'); }, 3000); }); return p; } Promise.race([ request(), timeout() ]) .then(res=>{ console.log(res) }).catch(err=>{ console.log(err)//网络不佳 })
Promise.prototype.then
Сценарий 1: следующий запрос зависит от результата предыдущего запроса
Описание: аналогично входу в апплет WeChat, вам сначала нужно выполнить вход в апплет WeChat wx.login, чтобы вернуть код, затем вызвать интерфейс входа, написанный бэкэндом, передать код, а затем вернуть токен, а затем каждый запрос должен нести токен, то есть следующий запрос зависит от данных, возвращенных предыдущим запросом
function A(){ return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve('B依赖的数据') },300) }) } function B(prams){ return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve(prams + 'C依赖的数据') },500) }) } function C(prams){ return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve(prams) },1000) }) } //我们期望的是走 try ,由于A B C模拟的请求中都是没有reject,用 try catch 捕获错误 try{ A().then( res=>B(res) ).then( res=>C(res) ).then( res=>{ console.log(res)//B依赖的数据C依赖的数据 }) } catch(e){ }
Сценарий приложения 2: использование функций промежуточного программного обеспечения
Описание: объем данных, возвращаемых интерфейсом, относительно велик, и он раздувается, чтобы обработать его в одном тогда.Каждому тогда предоставляется несколько данных рендеринга, чтобы они могли выполнять свои собственные обязанности.
//模拟后端返回的数据 let result = { bannerList:[ {img:'轮播图地址'} //... ], storeList:[ {name:'店铺列表'} //... ], categoryList:[ {name:'分类列表'} //... ], //... } function getInfo(){ return new Promise((resolve,reject)=>{ setTimeout(()=>{ resolve(result) },500) }) } getInfo().then(res=>{ let { bannerList } = res //渲染轮播图 console.log(bannerList) return res }).then(res=>{ let { storeList } = res //渲染店铺列表 console.log(storeList) return res }).then(res=>{ let { categoryList } = res console.log(categoryList) //渲染分类列表 return res })
Использованная литература:
Китайские обещания - JavaScript | MDN
Английские обещания - JavaScript | MDN
Эпилог
Если у вас есть лучшие идеи, пожалуйста, оставьте сообщение
Если в тексте есть неточности или ошибки, просьба указать
Прошлые статьи:
- когда все промисы в данной итерации разрешены