2016-06-18 1 views
2

Существует множество тем, которые обсуждают вопрос о гарантировании порядка выполнения обещаний в циклах. Я хотел бы знать, что является лучшей практикой в ​​JavaScript API для надстроек Office. Большую часть времени данное обещание ctx.sync().Лучший способ писать циклы с обещаниями (ctx.sync) в JavaScript API для Office

Ниже приведен фрагмент, который печатает адрес списка диапазонов Excel один за другим. Тест показывает, что он хорошо соответствует порядку диапазонов Excel. Но вопрос ли и как гарантировать порядок выполнения?

function loadAll() { 
    var ranges = ["A:A", "B:B", "C:C", "D:D", "E:E"]; 
    var sheet = "Sheet1"; 
    for (var i = 0; i < ranges.length; i++) { 
     loadRange(ranges[i], sheet);   
    } 
} 

function loadRange (range, sheet) { 
    Excel.run(function (ctx) { 
     var r = ctx.workbook.worksheets.getItem(sheet).getRange(range); 
     r.load('address'); 
     return ctx.sync().then(function() { 
      console.log(r.address); 
     }); 
    }); 
} 

Может ли кто-нибудь помочь?

+0

Почему вы заботитесь о порядке выполнения? Что возвращает 'Excel.run'? – Bergi

+0

Excel.run() выполняет пакетный скрипт, который выполняет действия над объектной моделью Excel. Пакетные команды включают определения локальных объектов прокси-сервера JavaScript и методы sync(), которые синхронизируют состояние между локальными объектами и объектами Excel и обеспечивают обещание. ([обзор] (http://dev.office.com/docs/add-ins/excel/excel-add-ins-javascript-programming-overview)) – SoftTimur

+0

Мне действительно нужен порядок выполнения ... потому что я собираюсь для некоторых сложных вещей внутри, а не 'loadRange' или' console.log (r.address) ', они зависят от порядка ... – SoftTimur

ответ

3

Потому что Excel.run возвращает Promise, вы можете связать его с помощью .then и заказать заказ. I.e.,

Excel.run(function(ctx) { ... return ctx.sync(); ... }) 
    .then(function() { 
     return Excel.run(function(ctx) { ... return ctx.sync(); ... }) 
    }) 
    .then(function() { 
     return Excel.run(function(ctx) { ... return ctx.sync(); ... }) 
    }); 

Это, как говорится ... это было бы довольно неэффективно. Гораздо лучше было бы, чтобы загрузить все объекты, которые нужно в одном пакете, создавая только один сетевой туда и обратно (что особенно важно с Excel онлайн ... но заметный даже на рабочем столе):

function loadAll() { 
    Excel.run(function(ctx) { 
     var ranges = ["A:A", "B:B", "C:C", "D:D", "E:E"]; 
     var sheet = "Sheet1"; 

     var loadedRanges = []; 
     for (var i = 0; i < ranges.length; i++) { 
      var r = ctx.workbook.worksheets.getItem(sheet).getRange(ranges[i]); 
      r.load('address'); 
      loadedRange.push(r); 
     } 

     return ctx.sync() 
      .then(function() { 
       for (var i = 0; i < loadedRanges.length; i++) { 
        console.log(loadedRanges[i].address); 
       } 
      }); 
    }); 
} 

UPDATE

Если, согласно комментарию, вы в конечном итоге нужно сделать отдельные задачи, которые зависят друг от друга, и каждый требуют туда и обратно, и, следовательно, действительно должны быть упорядочены с помощью цепочки Excel.run, я бы рекомендовал что-то следующим образом:

function loadAll() { 
    var ranges = ["A:A", "B:B", "C:C", "D:D", "E:E"]; 
    var sheet = "Sheet1"; 

    // Create a starter promise object 
    var promise = new OfficeExtension.Promise(function(resolve, reject) { resolve (null); }); 

    for (var i = 0; i < ranges.length; i++) { 
     // Create a closure over i, since it's used inside a function that won't be immediately executed. 
     (function(i) { 
      // Chain the promise by appending to it: 
      promise = promise.then(function() { 
       return loadRange(ranges[i], sheet); 
      }) 
     })(i);  
    } 
} 

function loadRange (range, sheet) { 
    return Excel.run(function (ctx) { 
     var r = ctx.workbook.worksheets.getItem(sheet).getRange(range); 
     r.load('address'); 
     return ctx.sync().then(function() { 
      console.log(r.address); 
     }); 
    }); 
} 

~ Michael Zlatkovsky, разработчик команды Office Extensibility, MSFT

+0

Загрузка адреса не является хорошим примером; На самом деле, я манипулирую значения и формулы ячейки шаг за шагом. Мне нужно связать «then» с помощью цикла для реализации последовательных асинхронных вызовов: значения ячейки и формулы в текущем 'then' зависят от манипуляции в предыдущем' then'; ожидается создание сетевого маршрута. В этом случае вы предлагаете рекурсию или 'Array.prototype.reduce()' или что-то еще? – SoftTimur

+0

См. Мой обновленный ответ –

+0

Благодарим вас за эту приятную структуру, Майкл ... Кроме того, я понимаю, что если мы добавим 'return prom' в конце' loadAll', мы могли бы добавить 'then' после' loadAll', например. , 'globalPromise.then (f1). then (f2). then (loadAll). then (f4) ...'. – SoftTimur

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