2014-12-01 1 views
4

Один из постов в разделе комментариев this блога машинопись пост говорит:Генераторы ES6 - это действительно альтернатива async/wait?

Если мне придется ждать до 2.0 для поддержки генератора ES6, я просто хочу палку с трейсер. Генераторы большое дело, они дают вам асинхронному/Await поддержка сегодня с использованием библиотек, такими как Коа, Co, Bluebird, и т.д.

асинхронных/ждем ключевых слова позволят приложениям сохранять логическую структуру, которая напоминает синхронный код. Как использовать генератор для достижения чего-то подобного? Например, как бы вы использовали генератор в сочетании с вызовом ajax для создания синхронного кода стиля, который позволяет избежать использования обратных вызовов?

+3

Это может помочь: http://davidwalsh.name/async-generators. async/await может быть реализован как синтаксический сахар над генераторами + обещания. –

+1

Вы просто смотрели на Коа, Ко и Синюю птицу? Они хорошо документированы. – Bergi

+0

Возможный дубликат [Понимание потока кода с выходом/генераторами] (http://stackoverflow.com/q/23551418/1048572) – Bergi

ответ

5

Вам просто нужно отвлечь это с помощью вспомогательной функции.

Предполагая JQuery:

function ajax(type, url, data){ 
    $.ajax({ 
    url: url, 
    data: data, 
    type: type 
    }) 
    .done(function(data) { 
    iterator.next(data); 
    }) 
    .fail(function() { 
    iterator.throw(); 
    }); 
} 
var get = ajax.bind(null, 'GET'); 
var post = ajax.bind(null, 'POST'); 
var put = ajax.bind(null, 'PUT'); 
var patch = ajax.bind(null, 'PATCH'); 
var del = ajax.bind(null, 'DELETE'); 

function *asyncGet() { 
    var URL = 'https://api.stackexchange.com/2.2/answers?order=desc&sort=activity&site=stackoverflow' 
    var data = yield get(URL); 
    console.log(data); 
} 

var iterator = asyncGet(); 
iterator.next(); 

Другой пример использования setTimeout:

function delayReturn(time, val){ 
    setTimeout(function(){ 
    iterator.next(val); 
    }, time); 
} 
var delayReturn1s = delayReturn.bind(null, 1000); 

function *main() { 
    console.log(yield delayReturn1s('Lolcat')); 
} 

var iterator = main(); 
iterator.next() 

Конечно, можно абстрагировать итератора попутно с чем-то вроде этого:

var async = function(generator){ 
    var resume = function(err, data){ 
    if (err) iterator.throw(); 
    iterator.next(data); 
    } 
    var iterator = generator(resume); 
    iterator.next(); 
} 

Тогда вы можете просто :

function ajax(type, url, data, cb){ 
    $.ajax({ 
    url: url, 
    data: data, 
    type: type 
    }) 
    .done(function(data) { 
    cb(null, data) 
    }) 
    .fail(function() { 
    cb(arguments); 
    }); 
} 
var get = ajax.bind(null, 'GET'); 
var post = ajax.bind(null, 'POST'); 
var put = ajax.bind(null, 'PUT'); 
var patch = ajax.bind(null, 'PATCH'); 
var del = ajax.bind(null, 'DELETE'); 

async(function *(resume) { 
    var URL = 'https://api.stackexchange.com/2.2/answers?order=desc&sort=activity&site=stackoverflow' 
    var data = yield get(URL, null, resume); 
    console.log(data); 
}); 
+3

Часть цели async/await - дать вам свободу писать синтаксически чистый код, не прибегая к «вариантам», подобным этому. Да, это в основном одно и то же, но на самом деле это не то же самое, потому что синтаксис ** так же важен как ** семантика ** с async/await. – jrista

+1

Конечно, это не одно и то же. OP спрашивал, как использовать генераторы для достижения async/await. – framp

+0

Действительно. Просто указывая на важное различие. Одна нота ... OP искал решение, которое не использует обратные вызовы ... функция async() по-прежнему требует обратного вызова. Любой способ избежать этого? – jrista

1

Например, как бы вы использовали генератор в сочетании с вызовом ajax для создания синхронного кода стиля, который позволяет избежать использования обратных вызовов?

От Beginning Node.js:


Как мысленный эксперимент представьте следующее, способ сказать выполнения JavaScript, чтобы приостановить выполнение кода на AWAIT ключевое слово, используемое на обещание и возобновить толькоодин раз (и если) погашено обещание, возвращаемое функцией.

// Not actual code. A thought experiment 
async function foo() { 
    try { 
     var val = await getMeAPromise(); 
     console.log(val); 
    } 
    catch(err){ 
     console.log('Error: ',err.message); 
    } 
} 

Когда обещание оседает выполнение продолжается, если оно было выполнено, то ждать будет возвращать значение, если она отвергнута ошибка будет выброшена синхронно, которые мы можем поймать. Это внезапно (и магически) делает асинхронное программирование так же просто, как синхронное программирование. Требуется три вещи:

  • Возможность приостановки выполнения функции.
  • Возможность возврата значения внутри функции.
  • Возможность бросить исключение внутри функции.

Хорошая новость заключается в том, что эта магия очень реальна, и сегодня можно попробовать. Синтаксис будет несколько иным, потому что технология, которую мы будем использовать, не была предназначена только для этого. Это возможно из-за генераторов JavaScript, технологии, поставляемой с ECMAScript 6, которую вы можете использовать сегодня.


генераторы позволяют приостановить выполнение функции (с помощью ключевого слова yield) возвращает значение внутри (с помощью функции .next(val)) и бросить и исключение внутри (с помощью функции .throw(err)). Эти API описаны в книге, и вы также можете просмотреть их на документации генератора. Тем не менее вы должны получить точку/мощность даже без понимания точного API, поскольку теперь вы знаете корреляцию.

+0

Существует несколько библиотек для асинхронного программирования использование генераторов, например https://github.com/bjouhier/galaxy. Но IMO - лучший вариант на данный момент [streamline.js] (https://github.com/Sage/streamlinejs), потому что он дает вам несколько вариантов для преобразованного исходного кода. Если вы вообще не заботитесь о совместимости с браузером, вы бы хотели пойти с обычным выходом ECMAScript 3, но у него также есть возможность генерировать генераторы ES6 (используя библиотеку «galaxy»). –

1

От блоге Томаса Хантера The long road to Async/Await in JavaScript

Этап 3: Генераторы/Урожайность (ES6) показывает пример использования генераторов ES6 сделать асинхронной JavaScript. Однако это только для демонстрации и, скорее всего, вы не хотите использовать эту технику. Использовать async/Ожидать вместо этого ES7 (экспериментальный) в ES5 traspiler, такой как Babel или TypeScript.

var generator = publishLevel(12, {data: true}); 

generator.next().value.then(function(user) { 
    return generator.next(user).value.then(function(can_create) { 
    return generator.next(can_create).value.then(function(level_result) { 
     console.log(level_result); 
    }); 
    }); 
}); 

function * publishLevel(user_id, level_data) { 
    var user = yield getUser(user_id); 
    var can_create = yield canCreate(user); 

    if (!can_create) { 
    return null; 
    } 

    var level = yield saveLevel(user, level_data); 

    return level; 
} 

function getUser(user_id) { 
    return new Promise(function(resolve) { 
    setTimeout(function() { 
     resolve({ 
     id: user_id, 
     nickname: 'tlhunter' 
     }); 
    }, 100); 
    }); 
} 

function canCreate(user) { 
    return new Promise(function(resolve) { 
    setTimeout(function() { 
     resolve(user.id === 12); 
    }, 100); 
    }); 
} 

function saveLevel(user, data) { 
    return new Promise(function(resolve) { 
    setTimeout(function() { 
     resolve({ 
     id: 100, 
     owner: user.nickname, 
     data: data 
     }); 
    }, 100); 
    }); 
} 
+0

Как вы используете async/wait с транспилером 6-5, когда они не являются частью ES6? – Bergi

+0

Он использует Promises за кулисами, поэтому он запускается в ES5. async/await - это, конечно, предложения, но некоторые транспилеры, такие как TypeScript, предоставляют вам варианты экспериментальной поддержки. – orad

+1

ОК, исправлено. Должен использовать ESAS (экспериментальный) для ES5 traspiler. – orad