javascript - AJAX calls sequenced by JS Promises appear to be running in the proper order, but the output from the database suggests otherwise -
i have 2 files i'm working here. query.php
script wrote handle mysql queries particular website. query_test.js
series of ajax calls test query.php
. query_test.js
, see below, uses promises sequence 1 test after another, have made tests dependent upon 1 another. writing console, ajax calls appear finishing in correct order. problem output inconsistent , output of individual tests not reflecting results of tests before them. since individual tests seem work fine, believe sequencing issue. can't figure out why , how happening.
for clarity, tests follows:
- test 1: retrieve entire table , display
- test 2: add new row, then retrieve , display table again
- test 3: select just-added row, display results
- test 4: update just-added row, retrieve , display table
- test 5: remove just-added row, retrieve , display table
in example output below, notice table retrieved after test 2 not reflect row added , test 3's query returns nothing. isn't until test 4 previously-added row seems show up. each execution yields different output; normal, , other times wrong above. console output always shows each call in order it's supposed be. makes me think in backend going wrong, i'm clueless is.
query.php
<?php /** purpose of script query database in number of ways. script should called via ajax. see below supported actions , required parameters each. -------- actions ($_post["action"])----------- 1. get_table: retrieve entire table - parameters: "table_name": [string] name of table - returns: [json] entire table 2. update_table: update row in table - parameters: "table_name": [string] name of table "queries": [array] list of queries, so: <column>[<relational_operator]<value> find rows update "values": [array] key=>value pairs each column updated. 3. select_table: select specified columns specified rows - parameters: "table_name": [string] name of table "queries": [array] list of queries, so: <column>[<relational_operator]<value> "columns": (optional) [array] list of column names returned. default value '*', or columns - returns: [json] rows returned query 4. add_row: add row table - parameters: "table_name": [string] name of table "values": [array] key=>value pairs of columns names , corresponding values new row 5. remove_row: remove row or rows table - parameters: "table_name": [string] name of table "queries": [array] list of queries, so: <column>[<relational_operator]<value> **/ // constants // actions define("get_table", 100); define("update_table", 101); define("select_table", 102); define("add_row", 103); define("remove_row", 104); $server = "localhost"; $username = "root"; $password = "password"; $db_name = "test"; $conn = new mysqli($server, $username, $password, $db_name); if ($conn->connect_error) die("connection failed: " . $conn->connect_error); // action must set checkpost("action") or die("error: post variable 'action' must setand not empty."); $action = $_post["action"]; // table name must given actions checkpost("table_name") or die("error: post variable 'table_name' must set , not empty."); $table = $_post["table_name"]; // generic error message $param_err = "error: ensure required params set , not empty."; // see action needs done switch ($action) { case get_table: // run query $q = "select * $table"; $result = $conn->query($q); $result or die("query '" . $q . "' failed: " . $conn->error); if ($result->num_rows > 0) { $output = array(); while ($row = $result->fetch_assoc()) { $output[] = $row; } echo json_encode($output); } break; case update_table: // check additional required params (checkpost("values") && checkpost("queries")) or die($param_err); $values = $_post["values"]; $queries = $_post["queries"]; $q = "update $table"; // add values set query $q .= " set "; addquotestostrings($values); additemstoquery($q, $values, true); // add clause @ end of query $q .= " "; additemstoquery($q, $queries, false); // ready send off query db , report success or failure $conn->query($q) or die("query '" . $q . "' failed: " . $conn->error); echo "successfully updated " . $conn->affected_rows . " rows."; break; case select_table: // check additional required params checkpost("queries") or die($param_err); $queries = $_post["queries"]; $q = "select "; // add columns if specified if (checkpost("columns")) { $columns = $_post["columns"]; additemstoquery($q, $columns, false); } else $q .= "* "; // no columns specified. select // add table name $q .= "from $table "; // add queries $q .= "where "; additemstoquery($q, $queries, false); // now, send off query $result = $conn->query($q); $result or die("query '" . $q . "' failed: " . $conn->error); if ($result->num_rows > 0) { $output = array(); while ($row = $result->fetch_assoc()) { $output[] = $row; } echo json_encode($output); } break; case add_row: // check post var "values" checkpost("values") or die($param_err); $values = $_post["values"]; $q = "insert $table"; // first, add column names $q .= " ("; additemstoquery($q, array_keys($values), false); $q .= ") "; // add values $q .= "values ("; addquotestostrings($values); additemstoquery($q, $values, false); $q .= ")"; // run query $conn->query($q) or die("query '" . $q . "' failed: " . $conn->error); echo "query successful."; break; case remove_row: // check queries checkpost("queries") or die($param_err); $queries = $_post["queries"]; $q = "delete $table"; // add queries $q .= " "; additemstoquery($q, $queries, false); // run query $conn->query($q) or die("query '" . $q . "' failed: " . $conn->error); echo "query affected " . $conn->affected_rows . " rows."; break; default: die("error: post variable 'action' has unknown value."); } /** adds items array sql query string assumes space present before last keyword of existing query. @param string &$q reference sql query string @param array $items array containing strings need added query in list format (e.g. item1,item2,item3) $param boolean $pairs boolean indicated whether items key=>value pairs or not **/ function additemstoquery(&$q, $items, $pairs) { $first = true; foreach ($items $name => $item) { if (!$first) $q .= ", "; else $first = false; $q .= $pairs ? $name . "=" . $item : $item; } } /** adds single quotes each string in array of items purpose of being added mysql query @param array $values reference array of items **/ function addquotestostrings(&$values) { foreach ($values &$value) { if (strcmp(gettype($value), "string") == 0) $value = "'" . $value . "'"; } unset($value); } /** simple helper function check if post var set , not empty @param string $name name of post variable **/ function checkpost($name) { return isset($_post[$name]) && !empty($_post[$name]); } ?>
query_test.js
// script series of ajax calls test query.php const get_table = 100; const update_table = 101; const select_table = 102; const add_row = 103; const remove_row = 104; /** runs ajax request query.php , displays result @param {jquery} div jquery object div place results @param {array} params assoc. array of post variables ajax call @param {boolean} displayastable determines result displayed table or @return {promise} promise object **/ function runtest(div, params, displayastable) { return promise.resolve($.post("../php/query.php", params, function(data) { // display result if (displayastable) { let tabledata = json.parse(data); let table = $('<table></table>'); (let rowkey in tabledata) { let row = $('<tr></tr>'); (let colkey in tabledata[rowkey]) { let col = $('<td></td>'); col.html(tabledata[rowkey][colkey]); row.append(col); } table.append(row); } div.append(table); } else div.append($('<p>' + data + '</p>')); })); } var num = 0; // temporary function test if promise order holds function logorder(test) { num++; console.log(test + " finished: " + num); } // ----------- test 1: retrieve table ---------------- let div = $('<div></div><br>'); let header = $('<h2>test 1: retrieve table</h2>'); div.append(header); $('body').append(div); let params = {action: get_table, table_name: "projects"}; var promise = runtest(div, params, true); // ------------ test 2: add row ---------------------- promise = promise.then(function(value) { logorder("test 1"); let div = $('<div></div><br>'); let header = $('<h2>test 2: add row</h2>'); div.append(header); $('body').append(div); let values = {title: "test_proj", pic: "none.jpg", brief: "testing", description: "this test"}; let params = {action: add_row, values: values, table_name: "projects"}; runtest(div, params, false); }, function(error) { alert(error); }); // table ensure row has been added promise = promise.then(function(value) { logorder("test 2"); let div = $('<div></div><br>'); $('body').append(div); let params = {action: get_table, table_name: "projects"}; runtest(div, params, true); }, function(error) { alert(error); }); // -------------- test 3: select table ------------------- promise = promise.then(function(value) { logorder("test 2 check"); let div = $('<div></div><br>'); let header = $('<h2>test 3: select table</h2>'); div.append(header); $('body').append(div); let queries = ["title='test_proj'"]; let params = {action: select_table, table_name: "projects", queries: queries}; runtest(div, params, true); }, function(error) { alert(error); }); // -------------- test 4: update table ------------------- promise = promise.then(function(value) { logorder("test 3"); let div = $('<div></div><br>'); let header = $('<h2>test 4: update table</h2>'); div.append(header); $('body').append(div); let queries = ["title='test_proj'"]; let values = {brief: "this updated", description: "this updated"}; let params = {action: update_table, table_name: "projects", queries: queries, values: values}; runtest(div, params, false); }, function(error) { alert(error); }); // table ensure table has been updated promise = promise.then(function(value) { logorder("test 4"); let div = $('<div></div><br>'); $('body').append(div); let params = {action: get_table, table_name: "projects"}; runtest(div, params, true); }, function(error) { alert(error); }); // -------------- test 5: remove row(s) ------------------ promise = promise.then(function(value) { logorder("test 4 check"); let div = $('<div></div><br>'); let header = $('<h2>test 5: remove row(s)</h2>'); div.append(header); $('body').append(div); let queries = ["title='test_proj'"]; let params = {action: remove_row, table_name: "projects", queries: queries}; runtest(div, params, false); }, function(error) { alert(error); }); // table ensure row has been removed promise = promise.then(function(value) { logorder("test 5"); let div = $('<div></div>'); $('body').append(div); let params = {action: get_table, table_name: "projects"}; runtest(div, params, true); }, function(error) { alert(error); }).then(function(value) { logorder("test 5 check"); }, function(error) { alert(error); });
example output:
test 1: retrieve table 11 placeholder none.jpg placeholder placeholder description test 2: add row query successful. 11 placeholder none.jpg placeholder placeholder description test 3: select table test 4: update table updated 1 rows. 11 placeholder none.jpg placeholder placeholder description 17 test_proj none.jpg updated updated test 5: remove row(s) query affected 1 rows. 11 placeholder none.jpg placeholder placeholder description
i figured out doing wrong after looking @ this.
i made changes suggested @darkknight, wasn't issue, or @ least wasn't issue.
it turns out needed return promise inside every promise.then()
success function. originally, wasn't doing this. after first test, each subsequent test starting query calling next then()
instead of waiting result since nothing being done new promise.
here new query_test.js
:
// script series of ajax calls test query.php const get_table = 100; const update_table = 101; const select_table = 102; const add_row = 103; const remove_row = 104; /** runs ajax request query.php , displays result @param {jquery} div jquery object div place results @param {array} params assoc. array of post variables ajax call @param {boolean} displayastable determines result displayed table or @return {promise} promise object **/ function runtest(div, params, displayastable) { return new promise(function(resolve, reject) { $.post("../php/query.php", params, function(data) { // display result if (displayastable) { let tabledata = json.parse(data); let table = $('<table></table>'); (let rowkey in tabledata) { let row = $('<tr></tr>'); (let colkey in tabledata[rowkey]) { let col = $('<td></td>'); col.html(tabledata[rowkey][colkey]); row.append(col); } table.append(row); } div.append(table); } else div.append($('<p>' + data + '</p>')); }).then(resolve, reject) }); } var num = 0; // temporary function test if promise order holds function logorder(test) { num++; console.log(test + " finished: " + num); } var promise = promise.resolve(); // ----------- test 1: retrieve table ---------------- promise = promise.then(function(value) { let div = $('<div></div><br>'); let header = $('<h2>test 1: retrieve table</h2>'); div.append(header); $('body').append(div); let params = {action: get_table, table_name: "projects"}; return runtest(div, params, true); }, function(error) { alert(error); }); // ------------ test 2: add row ---------------------- promise = promise.then(function(value) { logorder("test 1"); let div = $('<div></div><br>'); let header = $('<h2>test 2: add row</h2>'); div.append(header); $('body').append(div); let values = {title: "test_proj", pic: "none.jpg", brief: "testing", description: "this test"}; let params = {action: add_row, values: values, table_name: "projects"}; return runtest(div, params, false); }, function(error) { alert(error); }); // table ensure row has been added promise = promise.then(function(value) { logorder("test 2"); let div = $('<div></div><br>'); $('body').append(div); let params = {action: get_table, table_name: "projects"}; return runtest(div, params, true); }, function(error) { alert(error); }); // -------------- test 3: select table ------------------- promise = promise.then(function(value) { logorder("test 2 check"); let div = $('<div></div><br>'); let header = $('<h2>test 3: select table</h2>'); div.append(header); $('body').append(div); let queries = ["title='test_proj'"]; let params = {action: select_table, table_name: "projects", queries: queries}; return runtest(div, params, true); }, function(error) { alert(error); }); // -------------- test 4: update table ------------------- promise = promise.then(function(value) { logorder("test 3"); let div = $('<div></div><br>'); let header = $('<h2>test 4: update table</h2>'); div.append(header); $('body').append(div); let queries = ["title='test_proj'"]; let values = {brief: "this updated", description: "this updated"}; let params = {action: update_table, table_name: "projects", queries: queries, values: values}; return runtest(div, params, false); }, function(error) { alert(error); }); // table ensure table has been updated promise = promise.then(function(value) { logorder("test 4"); let div = $('<div></div><br>'); $('body').append(div); let params = {action: get_table, table_name: "projects"}; return runtest(div, params, true); }, function(error) { alert(error); }); // -------------- test 5: remove row(s) ------------------ promise = promise.then(function(value) { logorder("test 4 check"); let div = $('<div></div><br>'); let header = $('<h2>test 5: remove row(s)</h2>'); div.append(header); $('body').append(div); let queries = ["title='test_proj'"]; let params = {action: remove_row, table_name: "projects", queries: queries}; return runtest(div, params, false); }, function(error) { alert(error); }); // table ensure row has been removed promise = promise.then(function(value) { logorder("test 5"); let div = $('<div></div>'); $('body').append(div); let params = {action: get_table, table_name: "projects"}; return runtest(div, params, true); }, function(error) { alert(error); }); promise.then(function(value) { logorder("test 5 check"); }, function(error) { alert(error); });
Comments
Post a Comment