Предисловие: Всем привет, меня зовут Шао Вейру, всем нравится называть меня Сяо Шао, но я попал в яму программистов из-за своих увлечений.Купил первый вб в универе и сам выучил вб, и я наладил отношения с программированием. Неразрывная связь, затем самостоятельно выученный простой язык для написания игровых пособий и программного обеспечения для торговли, и я вошел в область переднего плана. Я видел, как многие друзья пишут статьи, чтобы поделиться ими, и я также сделал одну, чтобы играть. Следующие статьи являются чисто личным пониманием, которое удобно для записи и обучения.Должны быть недоразумения или недоразумения.Намерение состоит в том, чтобы стоять на плечах предшественников, делиться личным популярным пониманием технологии и расти вместе!
В будущем я продолжу обновлять аспект javascript и постараюсь максимально подробно описать систему путей обучения javascript.
Включая es6, angular, react, vue, nodejs, koa, express, официальный аккаунт и т. д., обычно используемые во внешнем интерфейсе.
Он будет написан от мелкого к глубокому, от начала к началу, я надеюсь, что каждый сможет что-то получить, и я надеюсь, что все обратят на меня внимание~
Адрес источника:GitHub.com/IA ms Nobody/prom…
Прежде чем читать эту статью, вы можете взглянуть на всю асинхронную разработкуnuggets.capable/post/684490…
Автор: Шао Вейру
Email: 166661688@qq.com
Wechat: 166661688
github: github.com/iamswr/
В основном говорят о генераторе и совместной библиотеке, асинхронном ожидании, совместном использовании.
Generator
Базовое использование генератора
Generator — это генератор, генерирующий итератор, который в основном используется для управления асинхронным процессом. В настоящее время генераторы редко встречаются в существующих библиотеках. В настоящее время основным генератором является библиотека redux-saga, koa1. 0 также использует генератор, но теперь он изменен на async/await.
Генератор генератора выглядит как обычная функция, но добавляет знак * перед именем функции.
function* say(){ // 在函数名前加 *
}
Функция генератора может быть приостановлена, в то время как обычная функция по умолчанию выполняет код до конца.Функция генератора может реализовать функцию паузы, когда она встречает yield внутренне, и использовать рядом с итерацией
function* say(){
yield 1
yield 2
yield 3
return 'end'
}
// 1.执行这个生成器看起来跟执行普通函数差不多,
// 但是实际上,执行这个生成器,会返回一个迭代器
let it = say()
// 2.此时it是一个迭代器 iterator,打印输出是 {}
console.log(it)
let obj1 = it.next()
// 3. 使用next进行迭代,打印输出 { value: 1, done: false }
// 可以看出,我们执行say生成器,用it来接收生成器返回的迭代器,
// 而通过迭代器it执行next(),会返回 { value: 1, done: false }
// 这里的value代表的是上面yield后的值,依次返回,
// done为false,意思是还没结束,后面还有yield或者return,当走到return时
// done会变为true,也就是完成了
console.log(obj1)
Давайте рассмотрим это полностью
function* say() {
let a = yield 1 // 第一个it.next()时返回
let b = yield 2 // 第二个it.next()时返回
let c = yield 3 // 第三个it.next()时返回
return 'end' // 第四个it.next()时返回
}
let it = say()
let obj1 = it.next()
console.log(obj1) // { value: 1, done: false }
let obj2 = it.next()
console.log(obj2) // { value: 2, done: false }
let obj3 = it.next()
console.log(obj3) // { value: 3, done: false }
let obj4 = it.next()
console.log(obj4) // { value: 'end', done: true }
Итератор, нам нужно перебирать один за другим, обычно мы будем перебирать следующие
function* say() {
let a = yield 1 // 第一个it.next()时返回
let b = yield 2 // 第二个it.next()时返回
let c = yield 3 // 第三个it.next()时返回
return 'end' // 第四个it.next()时返回
}
let it = say()
function next(){
let { value,done } = it.next()
console.log(value) // 依次打印输出 1 2 3 end
if(!done) next() // 直到迭代完成
}
next()
Благодаря приведенному выше примеру мы, вероятно, понимаем, как работает генератор.
Итак, давайте поговорим о том, как поместить вещи в генератор.
function* say() {
let a = yield 'hello swr1'
console.log(a)
let b = yield 'hello swr2'
console.log(b)
}
let it = say() // 返回迭代器
// 打印输出 { value: 'hello swr1', done: false }
// 此时执行迭代器的第一个next,会把上图红色圈的区域执行,并且输出'hello swr1'
// 此时需要注意的是let a = yield 'hello swr1',并非是把yield 'hello swr1'
// 赋值给a,那么a是什么时候被赋值呢?我们接着看下面
console.log(it.next())
// 打印输出 我是被传进来的1
// { value: 'hello swr2', done: false }
// 此时我们在next里传参,实际上就是当执行第二个next的时候,
// 会把上面蓝色圈的区域执行,而这个next的参数,
// 会被赋值给a,然后执行console.log(a),然后把'hello swr2'输出
console.log(it.next('我是被传进来的1'))
// 打印输出 我是被传进来的2
// { value: undefined, done: true }
// 此时我们第三次执行next,实际上就是当执行了第三个next的时候,
// 会把上面黄色圈的区域执行,而这个next的参数,
// 会被赋值给b,然后执行console.log(b),然后因为没有显式写return xxx,
// 会被默认返回undefined
console.log(it.next('我是被传进来的2'))
Пишу сюда, я так же озадачен, как и все остальные, какая польза от этой штуки, и очень громоздко перебирать один за другим следующий, поэтому поговорим о некоторых практических, генераторы можно использовать с промисами.
Использование генераторов с Promise и другими
Прежде чем я расскажу об использовании генераторов с Promise и другими, я расскажу о том, как писать функции на основе промисов, потому что в нашей повседневной разработке мы часто используем промисы.Нехорошо писать много кода после их использования. , так что будем считать. Чтобы написать общую функцию, можно изменить функцию callback-функции на promise
// 假设我们有3个文件,1.txt对应的内容为文本'2.txt'
2.txt对应的内容为文本'3.txt'
3.txt对应的内容为文本'hello swr'
let fs = require('fs')
// promise化函数
function promisify(fn){
return function(...args){
return new Promise((resolve,reject)=>{
fn(...args,(err,data)=>{ // node的api第一个参数为err
if(err) reject(err)
resolve(data)
})
})
}
}
// 把fs.readFile函数promise化
let read = promisify(fs.readFile)
read('1.txt','utf8').then((data)=>{
console.log(data) // 打印输出为 '2.txt'
})
Таким образом, мы выполнили общую функцию обещания.
Далее нам предстоит узнать о библиотеке co
Адрес библиотеки Co:github.com/tj/co
$ npm install co
// 本处代码promisify源用上面的函数promisify
// 本处代码read源用上面的函数read
let co = require('co')
function* r(){
let r1 = yield read('1.txt','utf8')
let r2 = yield read(r1,'utf8')
let r3 = yield read(r2,'utf8')
return r3
}
// 此时我们想取到r3,也就是3.txt里的内容'hello swr'
// 方法一:
let it = r()
let { value,done } = it.next() // value为一个promise对象
// 该对象会把resolve的值传给下一个then
value.then((data)=>{ // data值为'2.txt'
let { value,done } = it.next(data)
return value
}).then((data)=>{ // data值为'3.txt'
let { value,done } = it.next(data)
return value
}).then((data)=>{ // data值为'hello swr'
console.log(data) // 打印输出 'hello swr'
})
// 这样的写法,反而显得很繁琐复杂了,那么我们下面看下使用generator+co是怎么使用的
// 方法二:
co(r()).then(data=>{
console.log(data) // 打印输出 'hello swr'
})
// 是不是发现generator+co非常高效?
// 代码更像同步代码了,那么接下来我们自己实现一个co~
Как реализуется совместно?
function co(it){
return new Promise((resolve,reject)=>{
function next(data){
let { value,done } = it.next(data)
if(!done){
value.then((data)=>{
next(data)
},reject)
}else{
resolve(value)
}
}
next()
})
}
Когда есть две функции генератора, и одна вложена в другую
function* a(){
yield 1
}
function* b(){
// 1. 当我们想在generator b中嵌套generator a时,怎么嵌套呢?
// 2. yield *a(); ==> yield 1,实际上就是把yield 1 放在这个位置
// 在生成器函数中使用生成器函数 需要使用 *
yield *a()
yield 2
}
let it = b()
console.log(it.next())
async await
// 假设我们有3个文件,1.txt对应的内容为文本'2.txt'
2.txt对应的内容为文本'3.txt'
3.txt对应的内容为文本'hello swr'
async function r(){
try{
let r1 = await read('1.txt','utf8')
let r2 = await read(r1,'utf8')
let r3 = await read(r2,'utf8')
return r3
}catch(e){
console.log(e)
}
}
r().then((data)=>{
console.log(data) // hello swr
})
Вы обнаружили, что асинхронность + ожидание = генератор + сотрудничество?
async await решает проблему асинхронности
- Может сделать код синхронным
- Вы можете использовать попытку поймать
- можно использовать промисы
- Если let r1=await ждет промис, то результат промиса будет присвоен предыдущему r1, если let r1=await ждет нормальное значение, то обычное значение будет присвоено предыдущему r1
// 那么我想把上面的3个请求改为并发的呢?
let arr = Promise.all([read('1.txt','utf8'),read('2.txt','utf8'),read('3.txt','utf8')])
Так как же выглядит async await после компиляции babel?
'use strict';
var r = function () {
var _ref = _asyncToGenerator( // async await被编译成generator /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
var r1, r2, r3;
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.prev = 0;
_context.next = 3;
return read('100.txt', 'utf8');
case 3:
r1 = _context.sent;
_context.next = 6;
return read(r1, 'utf8');
case 6:
r2 = _context.sent;
_context.next = 9;
return read(r2, 'utf8');
case 9:
r3 = _context.sent;
return _context.abrupt('return', r3);
case 13:
_context.prev = 13;
_context.t0 = _context['catch'](0);
console.log(_context.t0);
case 16:
case 'end':
return _context.stop();
}
}
}, _callee, this, [[0, 13]]);
}));
return function r() {
return _ref.apply(this, arguments);
};
}();
function _asyncToGenerator(fn) {
return function () {
var gen = fn.apply(this, arguments);
return new Promise(function (resolve, reject) {
function step(key, arg) { // 相当于我们上门写的next函数
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error); return;
} if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); });
}
} return step("next");
});
};
}
У нас есть базовое понимание процесса асинхронной разработки из генератора обещаний обратного вызова async + await,
Далее мы используем пример, чтобы пробежаться по ним~
У нас есть требование, шаров соответственно 3, после того, как один шар выполнит анимацию, наступит очередь следующего шара выполнить анимацию и так далее.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.ball {
position: absolute;
width: 100px;
height: 100px;
background: red;
border-radius: 50%;
left: 0;
}
div:nth-child(1) {
top: 0px
}
div:nth-child(2) {
top: 120px
}
div:nth-child(3) {
top: 240px
}
</style>
</head>
<body>
<div>
<div class="ball"></div>
<div class="ball"></div>
<div class="ball"></div>
</div>
<script>
// 4.------------------// async await
let balls = document.querySelectorAll('.ball');
function move(ele, distance) {
return new Promise((resolve, reject) => {
let movex = 0;
let interval = setInterval(() => {
movex++;
ele.style.left = movex + 'px';
if (movex >= distance) {
resolve();
clearInterval(interval);
}
}, 6)
})
}
async function m() {
await move(balls[0], 500);
await move(balls[1], 400);
await move(balls[2], 300)
}
m().then(data=>{
alert('ok');
});
// 3.------------------// generator + co
// let balls = document.querySelectorAll('.ball');
// function move(ele, distance) {
// return new Promise((resolve, reject) => {
// let movex = 0;
// let interval = setInterval(() => {
// movex++;
// ele.style.left = movex + 'px';
// if (movex >= distance) {
// resolve();
// clearInterval(interval);
// }
// }, 6)
// })
// }
// function* m() {
// yield move(balls[0], 500);
// yield move(balls[1], 400);
// yield move(balls[2], 300)
// }
// function co(it) {
// return new Promise((resolve, reject) => {
// function next(data) {
// let { value, done } = it.next(data);
// if (!done) {
// value.then(data => {
// next(data);
// }, reject);
// }else{
// resolve(value);
// }
// }
// next();
// })
// }
// co(m()).then(data => {
// alert('done')
// })
// 2.------------------// promise
// let balls = document.querySelectorAll('.ball');
// function move(ele, distance) {
// return new Promise((resolve, reject) => {
// let movex = 0;
// let interval = setInterval(() => {
// movex++;
// ele.style.left = movex + 'px';
// if (movex >= distance) {
// resolve();
// clearInterval(interval);
// }
// }, 6)
// })
// }
// move(balls[0],500).then(data=>{
// return move(balls[1],400)
// }).then(data=>{
// return move(balls[2],300)
// }).then(data=>{
// alert('ok');
// })
// 1.------------------// callback
// let balls = document.querySelectorAll('.ball');
// function move(ele, distance, cb) {
// let movex = 0;
// let interval = setInterval(()=>{
// movex++;
// ele.style.left = movex+'px';
// if(movex >= distance){
// cb();
// clearInterval(interval);
// }
// },6)
// }
// move(balls[0], 500, function () {
// move(balls[1], 400, function () {
// move(balls[2], 300, function () {
// alert('成功')
// })
// })
// })
</script>
</body>
</html>