2015-04-12 8 views
10

Я использую babeljs с методами async/wait es7. У меня есть главный скрипт, который вызовет метод async в массиве объектов, которые возвращают обещания. Я использую Promise.all(), чтобы дождаться, пока все возвратятся, однако эти задачи могут занять много времени, и если они превысят порог, я бы хотел отменить все из них и обработать задачу соответствующим образом.Возможность прерывания асинхронного вызова

Есть ли способ для достижения такой цели? В настоящее время единственный способ, о котором я могу думать, - это создать процесс, который выполняет работу по вызову этих методов и дожидаясь их решения, и если срок достигнет, он может убить процесс и выполнить любую необходимую обработку.

Обновление: некоторые разъяснения об этих методах, которые ждут главный сценарий ... Они могут выполнять длинную серию операций (вызывая внешние системы, потоковые файлы где-то и т. Д.) И не выполняют одно действие, которое может быть выполнено отменяется независимо.

Update # 2: Некоторый непроверенный пол-псевдо-код

class Foo1 { 
    async doSomething() { 
     // call some external system 
     // copy some files 
     // put those files somewhere else (s3) 
    } 
} 
class Foo2 { 
    async doSomething() { 
     // Do some long computations 
     // Update some systems 
    } 
} 

class FooHandler { 
    constructor() { 
     this.fooList = []; 
    } 

    async start() { 
     await Promise.all(this.fooList.map(async (foo) => { 
      return await foo.doSomething(); 
     })); 
    } 
} 

let handler = new FooHandler(); 

handler.fooList.push(new Foo1()); 
handler.fooList.push(new Foo2()); 

// if this call takes too long because of slow connections, errors, whatever, 
// abort start(), handle it in whatever meaningful way, and continue on. 
await handler.start(); 
+1

Не могли бы вы высказать свой код? –

+1

Это отличный вопрос о реальной проблеме, почему она занижена? –

+0

related: [Как отменить цепочку обещаний EMCAScript6 (ванильный JavaScript)] (http://stackoverflow.com/q/29478751/1048572) – Bergi

ответ

7

Родной ES6 обещает в настоящее время не поддерживает отмену напрямую. Об этом постоянно говорят во многих местах, но его пока нет.

Поскольку местные обещания не поддерживают его, а async/await работает над обещаниями, в настоящее время нет встроенного в простой способ его прервать. Один общий подход - использовать токен при создании действия, возвращающего обещание.

Допустим, у Вас есть promisified XHR ПОЛУЧАЕТЕ:

// simplification 
function ajax(url){ 
    return new Promise((resolve, reject) => { 
     let xhr = new XMLHttpRequest; 
     xhr.open("GET", url); 
     xhr.onload =() => resolve(xhr.responseText); 
     xhr.onerror = reject; 
     xhr.send(); 
    }); 
} 

Теперь вы хотите использовать:

async function foo(){ 
    let result = await ajax("/myApi"); 
    let result2 = await ajax("/myApi2?token=" + result); 
} 

Теперь предположим, что мы хотим, чтобы отменить AJAX в некоторых случаях, мы можем передать маркер, как например:

function ajax(url, token = {}){ 
    return new Promise((resolve, reject) => { 
     let xhr = new XMLHttpRequest; 
     xhr.open("GET", url); 
     Object(token).cancel =() => { xhr.abort(), reject(); }; 
     xhr.onload =() => resolve(xhr.responseText); 
     xhr.onerror = reject; 
     xhr.send(); 
    }); 
} 

Это позволит вам сделать:

async function foo(){ 
    let token = {}; 
    let req = ajax("/myApi", token); // note no await 
    // now let's say we want to abort the request since we don't 
    // need the data 
    token.cancel(); // this will abort the token 
} 

Этот подход требует работы для работы с цепочкой, к счастью, с синтаксисом ES6 это не так уж и важно. Удачи и счастливого кодирования.

+0

Спасибо, это хорошая информация. Однако эти асинхронные методы могут в конечном итоге выполнять большую работу (скопировать файл из одного места в другое, сделать некоторые внешние вызовы, затем передать данные где-нибудь (например, отправить на s3), а затем выполнить некоторую работу по очистке). К сожалению, это не один вызов, который эти методы делают. –

+0

Совокупность жетонов. –

0

Это действительно зависит от API, который вам нужно использовать. Большинство современных методов асинхронного API-узла нелегко «прерывать» (readfileasync и т.п.), если только вы сами не выполняете их собственную реализацию.

Нет простого способа легко отменить запланированную отправку. API до сих пор не построен с этой целью. Обещания также не могут помочь, когда низкоуровневые реализации API не поддерживают прерывание.

Но в некоторых API вы можете перехватить «шаги» процесса, такие как потоки на событиях data и реализации «следующего тика». Там вы можете прервать дальнейшую обработку. (Потоки на самом деле довольно хорошие кандидаты для реализации перехвата IO)

Пример классического узла, где вычисление последовательности фибоначчи ввода «n» подается на запрос, логика реализуется с помощью «следующего тика».Там вы можете установить тайм-аут по расчету и сервер автоматически начинает долго выполняющиеся запросы:

var do_fibonacci_async = function(a,limiter,callback){ 
    if(limiter.halt){ 
     callback(limiter.msg); 
    } 
    else if(a <= 2){ 
     callback(limiter.halt ? limiter.msg : 1); 
    }else{ 
     process.nextTick(function(){ 
      do_fibonacci_async(a - 1,limiter, function(val1){ 
       do_fibonacci_async(a - 2,limiter, function(val2){ 
        callback(limiter.halt ? limiter.msg : val1+val2); 
       }); 
      }); 
     }); 
    } 
} 

exports.fibonacci_async = function(a,callback){ 
      if(!a || isNaN(a)){ 
     callback(new out("fibonacci", [], "")); 
     return; 
    } 

    var limiter = {halt:false, msg:"Too large to compute"}; 
    setTimeout(function(){ 
     limiter.halt = true; 
    },5000); 

    do_fibonacci_async(a,limiter,function(val){ 
     callback(new out("fibonacci", [a], val)); 
    }); 
} 
1

Если вы можете перейти на машинопись (в которой типы являются необязательными и ES6 и некоторые функции ES7 поддерживаются из коробки) вместо Babel и использовать обещания Bluebird, может быть достигнута семантика отмены, которую вы ищете.

Я создал простой модуль, который заменяет Машинопись __awaiter помощника по умолчанию тот, который поддерживает Bluebird отмен: https://www.npmjs.com/package/cancelable-awaiter

С его помощью вы можете использовать aync/Await синтаксис в сочетании с promise.cancel() и promise.finally() который Bluebird дает вам.

 Смежные вопросы

  • Нет связанных вопросов^_^