Форум программистов, компьютерный форум, киберфорум
JavaScript для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.91/75: Рейтинг темы: голосов - 75, средняя оценка - 4.91
0 / 0 / 2
Регистрация: 17.01.2011
Сообщений: 103

Promise, как дождаться выполнения

31.01.2019, 07:52. Показов 15431. Ответов 11

Студворк — интернет-сервис помощи студентам
Здравствуйте.
Есть код, у меня вместо setTimeout идет запись в indexedDB, но это не должно менять суть вещей.
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
console.clear();
function myPromise(val) {
  return new Promise(function(resolve, reject) {
    setTimeout(() => {
      resolve("--res"+val);
    }, val);
  });
}
 
function F1(){ console.log('1'); }
function F4(){ console.log('4'); }
 
let arr1 = {1:1, 2:2};
let arr2 = [1,2,3,4,5];
 
F1();
for (let key in arr1) {
  console.log('-2');
  arr2.forEach(function(item){
    myPromise(100+item)
      .then(function(res) {
        console.log(res);
      });
    console.log('--3');
  });
}
F4();
Сейчас выводится так:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1
-2
--3
--3
--3
--3
--3
-2
--3
--3
--3
--3
--3
4
--res101
--res101
--res102
--res102
--res103
--res103
--res104
--res104
--res105
--res105
Как сделать так, чтобы все выполнялось синхронно?
Вывод должен быть такой:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1
-2
--res101
--3
--res102
--3
--res103
--3
--res104
--3
--res105
--3
-2
--res101
--3
--res102
--3
--res103
--3
--res104
--3
--res105
--3
4
Добавлено через 5 часов 26 минут
Написал велосипед, но он работает только с одной итерацией цикла for-in. Если arr1 = {1:1, 2:2}, то runNextTask() выполняется асинхронно.
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
console.clear();
 
let arr1 = {1:1};
let arr2 = [1,2,3,4,5];
var cnt;
var memory = 1;
 
 
 
function myPromise(val) {
  return new Promise(function(resolve, reject) {
    setTimeout(() => {
      resolve("--res"+val);
    }, val);
  });
}
 
function F1(){ console.log('1'); }
function F4(){ console.log('4'); }
 
 
 
function loop() {
  for (let key in arr1) {
    console.log('-2');
    cnt = arr2.length;
    runNextTask();
  }
}
 
 
function runNextTask(){
  if(cnt-- > 0) {
    arr2.forEach(function(item, i){
      if (i != cnt) { return; }
      myPromise(1000+item)
        .then(function(res) {
        console.log(res);
        console.log('--3');
        runNextTask();
      });
    });
  }
}
 
 
F1();
loop();
F4();
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
31.01.2019, 07:52
Ответы с готовыми решениями:

Исправить порядок выполнения promise
function serverTalk () { var myInnerServerTalk = new Promise ( function (resolve,reject) { do { var zn...

Promise, два ajax запроса, задать очередь выполнения запросов, цепочка promise
Добрый день, уважаемые форумчане! Помогите разобраться с цепочкой promise. Суть проблемы: Есть 3 метода: 2 ajax get запроса и 1...

Дождаться выполнения AJAX запроса и вернуть значение
Делаю расширение для хрома. Мне нужно из моего файла content отправить сообщение на background и получить ответ. Отправляю из content...

11
Эксперт JS
6496 / 3907 / 2006
Регистрация: 14.06.2018
Сообщений: 6,781
31.01.2019, 09:02
Здравствуйте.
Технологию .then() и з .NET Framework 4.0 образца 2010 года нет смысла уже использовать. Практически устаревшая.

Сейчас актуальная технология async/await из .NET Framework 4.5 образца 2012 года.

Плюс имеет смысл использовать современную конструкцию foreach из C# 1.0 образца 2001 года.
В ES2015 она выглядит как for(let item of array)
PHP/HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
</head>
<body>
    <script>
        // Асинхронное ожидание из .NET Framework
        const delay = ms => new Promise((resolve) => { setTimeout(resolve, ms) });
 
        async function myPromise(val) {
            await delay(val);
            return "--res" + val;
        }
 
        function F1() { console.log('1'); }
        function F4() { console.log('4'); }
 
        // Сейчас функцию-терминальную ловушку асинхронности вызвать неоткуда,
        // поэтому её можно сделать IIFE или повесить обработчиком события загрузки страницы
        (async () => {
            console.clear();
            let arr1 = { 1: 1, 2: 2 };
            let arr2 = [1, 2, 3, 4, 5];
 
            F1(); // Безусловно в самом начале
            for (let key in arr1) { //Выполнить 2 раза. Значения элементов arr1 не используются
                console.log('-2');
                for (let item of arr2) { // Для каждого элемента массива arr2
                    let res = await myPromise(100 + item);
                    console.log(res);
                }
                console.log('--3'); // В конце каждого из двух раз
            }
            F4(); // Безусловно в самом конце
        })();
    </script>
</body>
</html>
Первоисточник для тщательного изучения:
Асинхронный шаблон, основанный на задачах (TAP)
Хорошим стартом может послужить и раздел на Метаните:
https://metanit.com/sharp/tutorial/13.3.php

Добавлено через 53 минуты
Похожая тема на Cyberforum со ссылкой на книгу Стивена Тауба, одного из авторов async/await:
Промисы и последовательное выполнение функций
1
0 / 0 / 2
Регистрация: 17.01.2011
Сообщений: 103
31.01.2019, 12:25  [ТС]
Хоть убейте, не понимаю.
Допустим у меня функция не setTimeout, а _add(arg), которая может возвращать ответ, а может и не делать этого.
Не понимаю, как в примере выше заменить setTimeout на _add. Что такое "resolve" в setTimeout(resolve, ms). Resolve - как я понимаю, должен быть вывод при успехе. Но зачем его запихнули в setTimeout? И почему без него не работает?
Мне кажется, я конкретно чего-то не понимаю.
JavaScript
1
2
3
4
function _add(key) {
  let request = db.transaction(['table'], "readwrite").objectStore('table').put(key);
  request.onsuccess = function(e) { console.log("_add > success > table"); };
}
Почему я не могу сделать так? _add - это же асинхронная функция. Я ей говорю подождать пока не закончишь выполнение. Почему она все равно выполняется асинхронно?
JavaScript
1
2
3
4
5
6
...
for (let item of arr2) {
    let tmp = { text: item };
    await _add(tmp);
 }
...
Для чего вызывать myPromise, чтобы потом вызвать delay?
0
Эксперт JS
6496 / 3907 / 2006
Регистрация: 14.06.2018
Сообщений: 6,781
31.01.2019, 13:36
Цитата Сообщение от Parallelogram Посмотреть сообщение
Допустим у меня функция не setTimeout, а _add(arg), которая может возвращать ответ, а может и не делать этого.
Цитата Сообщение от Parallelogram Посмотреть сообщение
Для чего вызывать myPromise, чтобы потом вызвать delay?
Описание функции myPromise:
JavaScript
1
2
3
4
async function myPromise(val) { // Принять параметр - количество миллисекунд
            await delay(val);  // Асинхронно подождать количество миллисекунд, не блокируя поток выполнения скрипта
            return "--res" + val; // Подготовить строчку с миллисекундами и вернуть эту строчку
        }
Функция состоит из двух инструкций, которые выполняет в нормальном для человека понимании.
Где здесь "может - не может" ? Функция честно выполнила две инструкции и закончила работу.

Добавлено через 3 минуты
Цитата Сообщение от Parallelogram Посмотреть сообщение
_add - это же асинхронная функция.
_add в данной реализации НЕ является асинхронной ни в каком понимании, ни в какой технологии асинхронности.
Состоит из двух инструкций - присвоить значение переменной, потом навесить обработчик на событие.
Обе инструкции выполняются синхронно.
1
0 / 0 / 2
Регистрация: 17.01.2011
Сообщений: 103
31.01.2019, 13:46  [ТС]
Цитата Сообщение от amr-now Посмотреть сообщение
_add в данной реализации НЕ является асинхронной ни в каком понимании, ни в какой технологии асинхронности.
В данном случае _add - это асинхронная функция, добавляет запись в базу данных (indexedDB).
0
Эксперт JS
6496 / 3907 / 2006
Регистрация: 14.06.2018
Сообщений: 6,781
31.01.2019, 13:55
Parallelogram, _add синхронная.
Можно сказать, что здесь реализован паттерн событийной асинхронной модели. Но сама функция _add как кусочек паттерна -синхронная.
0
0 / 0 / 2
Регистрация: 17.01.2011
Сообщений: 103
31.01.2019, 14:02  [ТС]
amr-now, Блин, тогда я просто недалекий человек.

Спасибо за попытку помочь мне.
0
Эксперт JS
6496 / 3907 / 2006
Регистрация: 14.06.2018
Сообщений: 6,781
31.01.2019, 14:08
Parallelogram, да. IndexedDB имеет API, основанный на Событийном Асинхронном Паттерне (EAP).
То есть вся работа заключается в классическом навешивании обработчиков событий.

Если хотите прочитать про EAP:
Обзор асинхронной модели, основанной на событиях
- пример асихронной загрузки картинки в технологии EAP
https://docs.microsoft.com/ru-... work-4.7.2
-------
То есть _add надо переделать под более современную технологию TAP.
0
249 / 162 / 68
Регистрация: 10.12.2017
Сообщений: 558
31.01.2019, 15:57
JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let a = [1, 2, 3, 4, 5]
 
let asyncIter = {
  [Symbol.asyncIterator]: async function* () {
    let asyncA = a.map((item, i) => new Promise(resolve => resolve(item)))
 
    while (asyncA.length) {
      yield await asyncA.shift()
    }
  }
}
 
proccess = async () => {
  for await (let item of asyncIter) {
    console.log(item)
  }
}
 
proccess()
0
0 / 0 / 2
Регистрация: 17.01.2011
Сообщений: 103
31.01.2019, 16:54  [ТС]
Evgen1337, да, через генератор сохраняется последовательное прохождение по массиву, и функция _add последовательно выполняется. Но вот только содержимое _add выполняется черте когда.
0
Эксперт JS
6496 / 3907 / 2006
Регистрация: 14.06.2018
Сообщений: 6,781
01.02.2019, 10:22
Лучший ответ Сообщение было отмечено Parallelogram как решение

Решение

Parallelogram, основной набор CRUD операций в indexedDB с простейшей реализацией постраничной выборки:
PHP/HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
</head>
<body>
    <script>
        class DB {
            static open(dbName, tableNames) {
                return new Promise((resolve, reject) => {
                    let request = indexedDB.open(dbName);
                    request.onsuccess = e => { resolve(request.result); }; // IDBDatabase
                    request.onerror = e => { reject(request.error) };
                    request.onupgradeneeded = e => {
                        let db = e.target.result;
                        for (let item of tableNames) {
                            if (!db.objectStoreNames.contains(item.name)) {
                                let store = db.createObjectStore(item.name, { keyPath: item.keyPath, autoIncrement: item.autoIncrement });
                            }
                        }
                    };
                });
            }
            static delete(dbName) {
                return new Promise((resolve, reject) => {
                    let request = indexedDB.deleteDatabase(dbName);
                    request.onsuccess = e => { resolve(request.result); }; // should be undefined
                    request.onerror = e => { reject(request.error) };
                });
            }
        }
        class DBTable {
            constructor(iDBDatabase, tableName) {
                this.db = iDBDatabase
                this.tableName = tableName;
            }
            add(...array) {
                return new Promise((resolve, reject) => {
                    let transaction = this.db.transaction([this.tableName], "readwrite"),
                        store = transaction.objectStore(this.tableName);
                    for (let item of array)
                        store.put(item);
                    transaction.oncomplete = e => { resolve(); };
                    transaction.onerror = e => { reject(transaction.error) };
                });
            }
            remove(key) {
                return new Promise((resolve, reject) => {
                    let transaction = this.db.transaction([this.tableName], "readwrite"),
                        store = transaction.objectStore(this.tableName);
                    store.delete(key);
                    transaction.oncomplete = e => { resolve(); };
                    transaction.onerror = e => { reject(transaction.error) };
                });
            }
            get rows() {
                return new Promise((resolve, reject) => {
                    let transaction = this.db.transaction([this.tableName], "readonly"),
                        store = transaction.objectStore(this.tableName),
                        request = store.getAll();
                    transaction.oncomplete = e => { resolve(request.result); };
                    transaction.onerror = e => { reject(transaction.error) };
                });
            }
            row(key) {
                return new Promise((resolve, reject) => {
                    let transaction = this.db.transaction([this.tableName], "readonly"),
                        store = transaction.objectStore(this.tableName),
                        request = store.get(key);
                    transaction.oncomplete = e => { resolve(request.result); };
                    transaction.onerror = e => { reject(transaction.error) };
                });
            }
            rowsWhere(predicate, shift = 0, take = 0) {
                return new Promise((resolve, reject) => {
                    let transaction = this.db.transaction([this.tableName], "readonly"),
                        store = transaction.objectStore(this.tableName),
                        cursor = store.openCursor(),
                        array = [];
                    cursor.onsuccess = (event) => {
                        var current = event.target.result;
                        if (current) {
                            if (!predicate || (predicate && predicate(current.value)))
                                array.push(current.value);
                            current.continue();
                        }
                    };
                    if (take || shift) {
                        if (take)
                            transaction.oncomplete = e => { resolve(array.filter((e, i) => i >= shift && i < shift + take)); };
                        else
                            transaction.oncomplete = e => { resolve(array.filter((e, i) => i >= shift)); };
                    }
                    else
                        transaction.oncomplete = e => { resolve(array); };
                    transaction.onerror = e => { reject(transaction.error) };
                });
            }
        }
 
        // Сейчас функцию-терминальную ловушку асинхронности вызвать неоткуда,
        // поэтому её можно сделать IIFE или повесить обработчиком события загрузки страницы
        (async () => {
            await DB.delete("myDB"); // Удалить БД, чтобы потом перестроить
            let db = await DB.open("myDB", [{ name: "products", keyPath: "id" }]);
            let table = new DBTable(db, "products");
 
            try {
                await table.add(
                    { id: 10, name: "Водка" },
                    { id: 20, name: "Колбаса" },
                    { id: 30, name: "Селёдка" }
                );
                console.log(await table.rows);
                console.log("-----------------");
                console.log(await table.row(10));
                console.log("-----------------");
                console.log(await table.rowsWhere(e => e.id > 10, 1));
                await table.remove(20);
                await table.remove(20); // Удаление чего-либо несуществующего не приводит к ошибке
                console.log("-----------------");
                console.log(await table.rows);
            }
            catch (e) {
                alert(e);
            }
        })();
    </script>
</body>
</html>
Чо-то как-то они накосовертили с API. Чердак действительно съезжает при сопоставлении с SQL.
----
Кстати. При добавлении нескольких строк в indexedDB в Opera 58 транзакция НЕ является атомарной операцией вопреки тому, что пишут в разнообразных статьях.
Прошу проверить в разных браузерах.
1
249 / 162 / 68
Регистрация: 10.12.2017
Сообщений: 558
01.02.2019, 11:40
Цитата Сообщение от Parallelogram Посмотреть сообщение
Evgen1337, да, через генератор сохраняется последовательное прохождение по массиву, и функция _add последовательно выполняется. Но вот только содержимое _add выполняется черте когда.
значит что-то сделано не так, или понято не так.

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
let a = [1, 2, 3, 4, 5]
 
let asyncIter = {
  [Symbol.asyncIterator]: async function* () {
    let asyncA = a.map(item => new Promise(resolve => setTimeout(resolve, 100, item)))
 
    while (asyncA.length) {
      yield await asyncA.shift()
    }
  }
}
 
process = async () => {
  for await (let item of asyncIter) {
    console.log(item)
  }
  // это будет выполнено после перебора Promise'ов...
  console.log('after process')
}
 
process()
// конечно, это будет выполнено до выполнения process()
console.log('im first')
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
01.02.2019, 11:40
Помогаю со студенческими работами здесь

Когда выполнятся .then/catch/finally после того как Promise завершится?
В учебнике написано А что здесь является текущим кодом? Когда витруальная машина начнет выполнять микрозадачи из очереди? Когда...

Как дождаться выполнения асинхронной функции?
Привет, Есть проэкт Node.js+angular+typescript. И у меня есть функция: window.speechSynthesis.speak(new...

Как дождаться выполнения скрипта от invokescript в webbrowser
Т.е. дождаться выполнения скрипта вызванного invokescript! Вот мой код: ...

Как стартовать несколько потоков и дождаться их выполнения
привет есть 4 метода хочу стартовать их и дождаться когда они все закончат подскажите как реализовать без изобретаия велосипеда ...

Как в цикле дождаться выполнения функции(клика)?
Добрый день. Имеется скрипт, который запрашивает данные из php, выводит на html страницу 3 кнопкокартинки и по клику на одну из них выдает...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL3_image
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
Влияние грибов на сукцессию
anaschu 26.01.2026
Бифуркационные изменения массы гриба происходят тогда, когда мы уменьшаем массу компоста в 10 раз, а скорость прироста биомассы уменьшаем в три раза. Скорость прироста биомассы может уменьшаться за. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru